github.com/ttys3/engine@v17.12.1-ce-rc2+incompatible/integration-cli/docker_cli_network_unix_test.go (about) 1 // +build !windows 2 3 package main 4 5 import ( 6 "encoding/json" 7 "fmt" 8 "io/ioutil" 9 "net" 10 "net/http" 11 "net/http/httptest" 12 "os" 13 "strings" 14 "time" 15 16 "github.com/docker/docker/api/types" 17 "github.com/docker/docker/api/types/versions/v1p20" 18 "github.com/docker/docker/integration-cli/checker" 19 "github.com/docker/docker/integration-cli/cli" 20 "github.com/docker/docker/integration-cli/daemon" 21 "github.com/docker/docker/pkg/stringid" 22 "github.com/docker/docker/runconfig" 23 "github.com/docker/libnetwork/driverapi" 24 remoteapi "github.com/docker/libnetwork/drivers/remote/api" 25 "github.com/docker/libnetwork/ipamapi" 26 remoteipam "github.com/docker/libnetwork/ipams/remote/api" 27 "github.com/docker/libnetwork/netlabel" 28 "github.com/go-check/check" 29 "github.com/gotestyourself/gotestyourself/icmd" 30 "github.com/vishvananda/netlink" 31 "golang.org/x/sys/unix" 32 ) 33 34 const dummyNetworkDriver = "dummy-network-driver" 35 const dummyIPAMDriver = "dummy-ipam-driver" 36 37 var remoteDriverNetworkRequest remoteapi.CreateNetworkRequest 38 39 func init() { 40 check.Suite(&DockerNetworkSuite{ 41 ds: &DockerSuite{}, 42 }) 43 } 44 45 type DockerNetworkSuite struct { 46 server *httptest.Server 47 ds *DockerSuite 48 d *daemon.Daemon 49 } 50 51 func (s *DockerNetworkSuite) SetUpTest(c *check.C) { 52 s.d = daemon.New(c, dockerBinary, dockerdBinary, daemon.Config{ 53 Experimental: testEnv.ExperimentalDaemon(), 54 }) 55 } 56 57 func (s *DockerNetworkSuite) TearDownTest(c *check.C) { 58 if s.d != nil { 59 s.d.Stop(c) 60 s.ds.TearDownTest(c) 61 } 62 } 63 64 func (s *DockerNetworkSuite) SetUpSuite(c *check.C) { 65 mux := http.NewServeMux() 66 s.server = httptest.NewServer(mux) 67 c.Assert(s.server, check.NotNil, check.Commentf("Failed to start an HTTP Server")) 68 setupRemoteNetworkDrivers(c, mux, s.server.URL, dummyNetworkDriver, dummyIPAMDriver) 69 } 70 71 func setupRemoteNetworkDrivers(c *check.C, mux *http.ServeMux, url, netDrv, ipamDrv string) { 72 73 mux.HandleFunc("/Plugin.Activate", func(w http.ResponseWriter, r *http.Request) { 74 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 75 fmt.Fprintf(w, `{"Implements": ["%s", "%s"]}`, driverapi.NetworkPluginEndpointType, ipamapi.PluginEndpointType) 76 }) 77 78 // Network driver implementation 79 mux.HandleFunc(fmt.Sprintf("/%s.GetCapabilities", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 80 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 81 fmt.Fprintf(w, `{"Scope":"local"}`) 82 }) 83 84 mux.HandleFunc(fmt.Sprintf("/%s.CreateNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 85 err := json.NewDecoder(r.Body).Decode(&remoteDriverNetworkRequest) 86 if err != nil { 87 http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest) 88 return 89 } 90 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 91 fmt.Fprintf(w, "null") 92 }) 93 94 mux.HandleFunc(fmt.Sprintf("/%s.DeleteNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 95 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 96 fmt.Fprintf(w, "null") 97 }) 98 99 mux.HandleFunc(fmt.Sprintf("/%s.CreateEndpoint", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 100 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 101 fmt.Fprintf(w, `{"Interface":{"MacAddress":"a0:b1:c2:d3:e4:f5"}}`) 102 }) 103 104 mux.HandleFunc(fmt.Sprintf("/%s.Join", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 105 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 106 107 veth := &netlink.Veth{ 108 LinkAttrs: netlink.LinkAttrs{Name: "randomIfName", TxQLen: 0}, PeerName: "cnt0"} 109 if err := netlink.LinkAdd(veth); err != nil { 110 fmt.Fprintf(w, `{"Error":"failed to add veth pair: `+err.Error()+`"}`) 111 } else { 112 fmt.Fprintf(w, `{"InterfaceName":{ "SrcName":"cnt0", "DstPrefix":"veth"}}`) 113 } 114 }) 115 116 mux.HandleFunc(fmt.Sprintf("/%s.Leave", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 117 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 118 fmt.Fprintf(w, "null") 119 }) 120 121 mux.HandleFunc(fmt.Sprintf("/%s.DeleteEndpoint", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 122 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 123 if link, err := netlink.LinkByName("cnt0"); err == nil { 124 netlink.LinkDel(link) 125 } 126 fmt.Fprintf(w, "null") 127 }) 128 129 // IPAM Driver implementation 130 var ( 131 poolRequest remoteipam.RequestPoolRequest 132 poolReleaseReq remoteipam.ReleasePoolRequest 133 addressRequest remoteipam.RequestAddressRequest 134 addressReleaseReq remoteipam.ReleaseAddressRequest 135 lAS = "localAS" 136 gAS = "globalAS" 137 pool = "172.28.0.0/16" 138 poolID = lAS + "/" + pool 139 gw = "172.28.255.254/16" 140 ) 141 142 mux.HandleFunc(fmt.Sprintf("/%s.GetDefaultAddressSpaces", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 143 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 144 fmt.Fprintf(w, `{"LocalDefaultAddressSpace":"`+lAS+`", "GlobalDefaultAddressSpace": "`+gAS+`"}`) 145 }) 146 147 mux.HandleFunc(fmt.Sprintf("/%s.RequestPool", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 148 err := json.NewDecoder(r.Body).Decode(&poolRequest) 149 if err != nil { 150 http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest) 151 return 152 } 153 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 154 if poolRequest.AddressSpace != lAS && poolRequest.AddressSpace != gAS { 155 fmt.Fprintf(w, `{"Error":"Unknown address space in pool request: `+poolRequest.AddressSpace+`"}`) 156 } else if poolRequest.Pool != "" && poolRequest.Pool != pool { 157 fmt.Fprintf(w, `{"Error":"Cannot handle explicit pool requests yet"}`) 158 } else { 159 fmt.Fprintf(w, `{"PoolID":"`+poolID+`", "Pool":"`+pool+`"}`) 160 } 161 }) 162 163 mux.HandleFunc(fmt.Sprintf("/%s.RequestAddress", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 164 err := json.NewDecoder(r.Body).Decode(&addressRequest) 165 if err != nil { 166 http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest) 167 return 168 } 169 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 170 // make sure libnetwork is now querying on the expected pool id 171 if addressRequest.PoolID != poolID { 172 fmt.Fprintf(w, `{"Error":"unknown pool id"}`) 173 } else if addressRequest.Address != "" { 174 fmt.Fprintf(w, `{"Error":"Cannot handle explicit address requests yet"}`) 175 } else { 176 fmt.Fprintf(w, `{"Address":"`+gw+`"}`) 177 } 178 }) 179 180 mux.HandleFunc(fmt.Sprintf("/%s.ReleaseAddress", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 181 err := json.NewDecoder(r.Body).Decode(&addressReleaseReq) 182 if err != nil { 183 http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest) 184 return 185 } 186 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 187 // make sure libnetwork is now asking to release the expected address from the expected poolid 188 if addressRequest.PoolID != poolID { 189 fmt.Fprintf(w, `{"Error":"unknown pool id"}`) 190 } else if addressReleaseReq.Address != gw { 191 fmt.Fprintf(w, `{"Error":"unknown address"}`) 192 } else { 193 fmt.Fprintf(w, "null") 194 } 195 }) 196 197 mux.HandleFunc(fmt.Sprintf("/%s.ReleasePool", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 198 err := json.NewDecoder(r.Body).Decode(&poolReleaseReq) 199 if err != nil { 200 http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest) 201 return 202 } 203 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 204 // make sure libnetwork is now asking to release the expected poolid 205 if addressRequest.PoolID != poolID { 206 fmt.Fprintf(w, `{"Error":"unknown pool id"}`) 207 } else { 208 fmt.Fprintf(w, "null") 209 } 210 }) 211 212 err := os.MkdirAll("/etc/docker/plugins", 0755) 213 c.Assert(err, checker.IsNil) 214 215 fileName := fmt.Sprintf("/etc/docker/plugins/%s.spec", netDrv) 216 err = ioutil.WriteFile(fileName, []byte(url), 0644) 217 c.Assert(err, checker.IsNil) 218 219 ipamFileName := fmt.Sprintf("/etc/docker/plugins/%s.spec", ipamDrv) 220 err = ioutil.WriteFile(ipamFileName, []byte(url), 0644) 221 c.Assert(err, checker.IsNil) 222 } 223 224 func (s *DockerNetworkSuite) TearDownSuite(c *check.C) { 225 if s.server == nil { 226 return 227 } 228 229 s.server.Close() 230 231 err := os.RemoveAll("/etc/docker/plugins") 232 c.Assert(err, checker.IsNil) 233 } 234 235 func assertNwIsAvailable(c *check.C, name string) { 236 if !isNwPresent(c, name) { 237 c.Fatalf("Network %s not found in network ls o/p", name) 238 } 239 } 240 241 func assertNwNotAvailable(c *check.C, name string) { 242 if isNwPresent(c, name) { 243 c.Fatalf("Found network %s in network ls o/p", name) 244 } 245 } 246 247 func isNwPresent(c *check.C, name string) bool { 248 out, _ := dockerCmd(c, "network", "ls") 249 lines := strings.Split(out, "\n") 250 for i := 1; i < len(lines)-1; i++ { 251 netFields := strings.Fields(lines[i]) 252 if netFields[1] == name { 253 return true 254 } 255 } 256 return false 257 } 258 259 // assertNwList checks network list retrieved with ls command 260 // equals to expected network list 261 // note: out should be `network ls [option]` result 262 func assertNwList(c *check.C, out string, expectNws []string) { 263 lines := strings.Split(out, "\n") 264 var nwList []string 265 for _, line := range lines[1 : len(lines)-1] { 266 netFields := strings.Fields(line) 267 // wrap all network name in nwList 268 nwList = append(nwList, netFields[1]) 269 } 270 271 // network ls should contains all expected networks 272 c.Assert(nwList, checker.DeepEquals, expectNws) 273 } 274 275 func getNwResource(c *check.C, name string) *types.NetworkResource { 276 out, _ := dockerCmd(c, "network", "inspect", name) 277 nr := []types.NetworkResource{} 278 err := json.Unmarshal([]byte(out), &nr) 279 c.Assert(err, check.IsNil) 280 return &nr[0] 281 } 282 283 func (s *DockerNetworkSuite) TestDockerNetworkLsDefault(c *check.C) { 284 defaults := []string{"bridge", "host", "none"} 285 for _, nn := range defaults { 286 assertNwIsAvailable(c, nn) 287 } 288 } 289 290 func (s *DockerNetworkSuite) TestDockerNetworkCreatePredefined(c *check.C) { 291 predefined := []string{"bridge", "host", "none", "default"} 292 for _, net := range predefined { 293 // predefined networks can't be created again 294 out, _, err := dockerCmdWithError("network", "create", net) 295 c.Assert(err, checker.NotNil, check.Commentf("%v", out)) 296 } 297 } 298 299 func (s *DockerNetworkSuite) TestDockerNetworkCreateHostBind(c *check.C) { 300 dockerCmd(c, "network", "create", "--subnet=192.168.10.0/24", "--gateway=192.168.10.1", "-o", "com.docker.network.bridge.host_binding_ipv4=192.168.10.1", "testbind") 301 assertNwIsAvailable(c, "testbind") 302 303 out := runSleepingContainer(c, "--net=testbind", "-p", "5000:5000") 304 id := strings.TrimSpace(out) 305 c.Assert(waitRun(id), checker.IsNil) 306 out, _ = dockerCmd(c, "ps") 307 c.Assert(out, checker.Contains, "192.168.10.1:5000->5000/tcp") 308 } 309 310 func (s *DockerNetworkSuite) TestDockerNetworkRmPredefined(c *check.C) { 311 predefined := []string{"bridge", "host", "none", "default"} 312 for _, net := range predefined { 313 // predefined networks can't be removed 314 out, _, err := dockerCmdWithError("network", "rm", net) 315 c.Assert(err, checker.NotNil, check.Commentf("%v", out)) 316 } 317 } 318 319 func (s *DockerNetworkSuite) TestDockerNetworkLsFilter(c *check.C) { 320 testRequires(c, OnlyDefaultNetworks) 321 testNet := "testnet1" 322 testLabel := "foo" 323 testValue := "bar" 324 out, _ := dockerCmd(c, "network", "create", "dev") 325 defer func() { 326 dockerCmd(c, "network", "rm", "dev") 327 dockerCmd(c, "network", "rm", testNet) 328 }() 329 networkID := strings.TrimSpace(out) 330 331 // filter with partial ID 332 // only show 'dev' network 333 out, _ = dockerCmd(c, "network", "ls", "-f", "id="+networkID[0:5]) 334 assertNwList(c, out, []string{"dev"}) 335 336 out, _ = dockerCmd(c, "network", "ls", "-f", "name=dge") 337 assertNwList(c, out, []string{"bridge"}) 338 339 // only show built-in network (bridge, none, host) 340 out, _ = dockerCmd(c, "network", "ls", "-f", "type=builtin") 341 assertNwList(c, out, []string{"bridge", "host", "none"}) 342 343 // only show custom networks (dev) 344 out, _ = dockerCmd(c, "network", "ls", "-f", "type=custom") 345 assertNwList(c, out, []string{"dev"}) 346 347 // show all networks with filter 348 // it should be equivalent of ls without option 349 out, _ = dockerCmd(c, "network", "ls", "-f", "type=custom", "-f", "type=builtin") 350 assertNwList(c, out, []string{"bridge", "dev", "host", "none"}) 351 352 out, _ = dockerCmd(c, "network", "create", "--label", testLabel+"="+testValue, testNet) 353 assertNwIsAvailable(c, testNet) 354 355 out, _ = dockerCmd(c, "network", "ls", "-f", "label="+testLabel) 356 assertNwList(c, out, []string{testNet}) 357 358 out, _ = dockerCmd(c, "network", "ls", "-f", "label="+testLabel+"="+testValue) 359 assertNwList(c, out, []string{testNet}) 360 361 out, _ = dockerCmd(c, "network", "ls", "-f", "label=nonexistent") 362 outArr := strings.Split(strings.TrimSpace(out), "\n") 363 c.Assert(len(outArr), check.Equals, 1, check.Commentf("%s\n", out)) 364 365 out, _ = dockerCmd(c, "network", "ls", "-f", "driver=null") 366 assertNwList(c, out, []string{"none"}) 367 368 out, _ = dockerCmd(c, "network", "ls", "-f", "driver=host") 369 assertNwList(c, out, []string{"host"}) 370 371 out, _ = dockerCmd(c, "network", "ls", "-f", "driver=bridge") 372 assertNwList(c, out, []string{"bridge", "dev", testNet}) 373 } 374 375 func (s *DockerNetworkSuite) TestDockerNetworkCreateDelete(c *check.C) { 376 dockerCmd(c, "network", "create", "test") 377 assertNwIsAvailable(c, "test") 378 379 dockerCmd(c, "network", "rm", "test") 380 assertNwNotAvailable(c, "test") 381 } 382 383 func (s *DockerNetworkSuite) TestDockerNetworkCreateLabel(c *check.C) { 384 testNet := "testnetcreatelabel" 385 testLabel := "foo" 386 testValue := "bar" 387 388 dockerCmd(c, "network", "create", "--label", testLabel+"="+testValue, testNet) 389 assertNwIsAvailable(c, testNet) 390 391 out, _, err := dockerCmdWithError("network", "inspect", "--format={{ .Labels."+testLabel+" }}", testNet) 392 c.Assert(err, check.IsNil) 393 c.Assert(strings.TrimSpace(out), check.Equals, testValue) 394 395 dockerCmd(c, "network", "rm", testNet) 396 assertNwNotAvailable(c, testNet) 397 } 398 399 func (s *DockerSuite) TestDockerNetworkDeleteNotExists(c *check.C) { 400 out, _, err := dockerCmdWithError("network", "rm", "test") 401 c.Assert(err, checker.NotNil, check.Commentf("%v", out)) 402 } 403 404 func (s *DockerSuite) TestDockerNetworkDeleteMultiple(c *check.C) { 405 dockerCmd(c, "network", "create", "testDelMulti0") 406 assertNwIsAvailable(c, "testDelMulti0") 407 dockerCmd(c, "network", "create", "testDelMulti1") 408 assertNwIsAvailable(c, "testDelMulti1") 409 dockerCmd(c, "network", "create", "testDelMulti2") 410 assertNwIsAvailable(c, "testDelMulti2") 411 out, _ := dockerCmd(c, "run", "-d", "--net", "testDelMulti2", "busybox", "top") 412 containerID := strings.TrimSpace(out) 413 waitRun(containerID) 414 415 // delete three networks at the same time, since testDelMulti2 416 // contains active container, its deletion should fail. 417 out, _, err := dockerCmdWithError("network", "rm", "testDelMulti0", "testDelMulti1", "testDelMulti2") 418 // err should not be nil due to deleting testDelMulti2 failed. 419 c.Assert(err, checker.NotNil, check.Commentf("out: %s", out)) 420 // testDelMulti2 should fail due to network has active endpoints 421 c.Assert(out, checker.Contains, "has active endpoints") 422 assertNwNotAvailable(c, "testDelMulti0") 423 assertNwNotAvailable(c, "testDelMulti1") 424 // testDelMulti2 can't be deleted, so it should exist 425 assertNwIsAvailable(c, "testDelMulti2") 426 } 427 428 func (s *DockerSuite) TestDockerNetworkInspect(c *check.C) { 429 out, _ := dockerCmd(c, "network", "inspect", "host") 430 networkResources := []types.NetworkResource{} 431 err := json.Unmarshal([]byte(out), &networkResources) 432 c.Assert(err, check.IsNil) 433 c.Assert(networkResources, checker.HasLen, 1) 434 435 out, _ = dockerCmd(c, "network", "inspect", "--format={{ .Name }}", "host") 436 c.Assert(strings.TrimSpace(out), check.Equals, "host") 437 } 438 439 func (s *DockerSuite) TestDockerNetworkInspectWithID(c *check.C) { 440 out, _ := dockerCmd(c, "network", "create", "test2") 441 networkID := strings.TrimSpace(out) 442 assertNwIsAvailable(c, "test2") 443 out, _ = dockerCmd(c, "network", "inspect", "--format={{ .Id }}", "test2") 444 c.Assert(strings.TrimSpace(out), check.Equals, networkID) 445 446 out, _ = dockerCmd(c, "network", "inspect", "--format={{ .ID }}", "test2") 447 c.Assert(strings.TrimSpace(out), check.Equals, networkID) 448 } 449 450 func (s *DockerSuite) TestDockerInspectMultipleNetwork(c *check.C) { 451 result := dockerCmdWithResult("network", "inspect", "host", "none") 452 result.Assert(c, icmd.Success) 453 454 networkResources := []types.NetworkResource{} 455 err := json.Unmarshal([]byte(result.Stdout()), &networkResources) 456 c.Assert(err, check.IsNil) 457 c.Assert(networkResources, checker.HasLen, 2) 458 } 459 460 func (s *DockerSuite) TestDockerInspectMultipleNetworksIncludingNonexistent(c *check.C) { 461 // non-existent network was not at the beginning of the inspect list 462 // This should print an error, return an exitCode 1 and print the host network 463 result := dockerCmdWithResult("network", "inspect", "host", "nonexistent") 464 result.Assert(c, icmd.Expected{ 465 ExitCode: 1, 466 Err: "Error: No such network: nonexistent", 467 Out: "host", 468 }) 469 470 networkResources := []types.NetworkResource{} 471 err := json.Unmarshal([]byte(result.Stdout()), &networkResources) 472 c.Assert(err, check.IsNil) 473 c.Assert(networkResources, checker.HasLen, 1) 474 475 // Only one non-existent network to inspect 476 // Should print an error and return an exitCode, nothing else 477 result = dockerCmdWithResult("network", "inspect", "nonexistent") 478 result.Assert(c, icmd.Expected{ 479 ExitCode: 1, 480 Err: "Error: No such network: nonexistent", 481 Out: "[]", 482 }) 483 484 // non-existent network was at the beginning of the inspect list 485 // Should not fail fast, and still print host network but print an error 486 result = dockerCmdWithResult("network", "inspect", "nonexistent", "host") 487 result.Assert(c, icmd.Expected{ 488 ExitCode: 1, 489 Err: "Error: No such network: nonexistent", 490 Out: "host", 491 }) 492 493 networkResources = []types.NetworkResource{} 494 err = json.Unmarshal([]byte(result.Stdout()), &networkResources) 495 c.Assert(err, check.IsNil) 496 c.Assert(networkResources, checker.HasLen, 1) 497 } 498 499 func (s *DockerSuite) TestDockerInspectNetworkWithContainerName(c *check.C) { 500 dockerCmd(c, "network", "create", "brNetForInspect") 501 assertNwIsAvailable(c, "brNetForInspect") 502 defer func() { 503 dockerCmd(c, "network", "rm", "brNetForInspect") 504 assertNwNotAvailable(c, "brNetForInspect") 505 }() 506 507 out, _ := dockerCmd(c, "run", "-d", "--name", "testNetInspect1", "--net", "brNetForInspect", "busybox", "top") 508 c.Assert(waitRun("testNetInspect1"), check.IsNil) 509 containerID := strings.TrimSpace(out) 510 defer func() { 511 // we don't stop container by name, because we'll rename it later 512 dockerCmd(c, "stop", containerID) 513 }() 514 515 out, _ = dockerCmd(c, "network", "inspect", "brNetForInspect") 516 networkResources := []types.NetworkResource{} 517 err := json.Unmarshal([]byte(out), &networkResources) 518 c.Assert(err, check.IsNil) 519 c.Assert(networkResources, checker.HasLen, 1) 520 container, ok := networkResources[0].Containers[containerID] 521 c.Assert(ok, checker.True) 522 c.Assert(container.Name, checker.Equals, "testNetInspect1") 523 524 // rename container and check docker inspect output update 525 newName := "HappyNewName" 526 dockerCmd(c, "rename", "testNetInspect1", newName) 527 528 // check whether network inspect works properly 529 out, _ = dockerCmd(c, "network", "inspect", "brNetForInspect") 530 newNetRes := []types.NetworkResource{} 531 err = json.Unmarshal([]byte(out), &newNetRes) 532 c.Assert(err, check.IsNil) 533 c.Assert(newNetRes, checker.HasLen, 1) 534 container1, ok := newNetRes[0].Containers[containerID] 535 c.Assert(ok, checker.True) 536 c.Assert(container1.Name, checker.Equals, newName) 537 538 } 539 540 func (s *DockerNetworkSuite) TestDockerNetworkConnectDisconnect(c *check.C) { 541 dockerCmd(c, "network", "create", "test") 542 assertNwIsAvailable(c, "test") 543 nr := getNwResource(c, "test") 544 545 c.Assert(nr.Name, checker.Equals, "test") 546 c.Assert(len(nr.Containers), checker.Equals, 0) 547 548 // run a container 549 out, _ := dockerCmd(c, "run", "-d", "--name", "test", "busybox", "top") 550 c.Assert(waitRun("test"), check.IsNil) 551 containerID := strings.TrimSpace(out) 552 553 // connect the container to the test network 554 dockerCmd(c, "network", "connect", "test", containerID) 555 556 // inspect the network to make sure container is connected 557 nr = getNetworkResource(c, nr.ID) 558 c.Assert(len(nr.Containers), checker.Equals, 1) 559 c.Assert(nr.Containers[containerID], check.NotNil) 560 561 // check if container IP matches network inspect 562 ip, _, err := net.ParseCIDR(nr.Containers[containerID].IPv4Address) 563 c.Assert(err, check.IsNil) 564 containerIP := findContainerIP(c, "test", "test") 565 c.Assert(ip.String(), checker.Equals, containerIP) 566 567 // disconnect container from the network 568 dockerCmd(c, "network", "disconnect", "test", containerID) 569 nr = getNwResource(c, "test") 570 c.Assert(nr.Name, checker.Equals, "test") 571 c.Assert(len(nr.Containers), checker.Equals, 0) 572 573 // run another container 574 out, _ = dockerCmd(c, "run", "-d", "--net", "test", "--name", "test2", "busybox", "top") 575 c.Assert(waitRun("test2"), check.IsNil) 576 containerID = strings.TrimSpace(out) 577 578 nr = getNwResource(c, "test") 579 c.Assert(nr.Name, checker.Equals, "test") 580 c.Assert(len(nr.Containers), checker.Equals, 1) 581 582 // force disconnect the container to the test network 583 dockerCmd(c, "network", "disconnect", "-f", "test", containerID) 584 585 nr = getNwResource(c, "test") 586 c.Assert(nr.Name, checker.Equals, "test") 587 c.Assert(len(nr.Containers), checker.Equals, 0) 588 589 dockerCmd(c, "network", "rm", "test") 590 assertNwNotAvailable(c, "test") 591 } 592 593 func (s *DockerNetworkSuite) TestDockerNetworkIPAMMultipleNetworks(c *check.C) { 594 testRequires(c, SameHostDaemon) 595 // test0 bridge network 596 dockerCmd(c, "network", "create", "--subnet=192.168.0.0/16", "test1") 597 assertNwIsAvailable(c, "test1") 598 599 // test2 bridge network does not overlap 600 dockerCmd(c, "network", "create", "--subnet=192.169.0.0/16", "test2") 601 assertNwIsAvailable(c, "test2") 602 603 // for networks w/o ipam specified, docker will choose proper non-overlapping subnets 604 dockerCmd(c, "network", "create", "test3") 605 assertNwIsAvailable(c, "test3") 606 dockerCmd(c, "network", "create", "test4") 607 assertNwIsAvailable(c, "test4") 608 dockerCmd(c, "network", "create", "test5") 609 assertNwIsAvailable(c, "test5") 610 611 // test network with multiple subnets 612 // bridge network doesn't support multiple subnets. hence, use a dummy driver that supports 613 614 dockerCmd(c, "network", "create", "-d", dummyNetworkDriver, "--subnet=192.168.0.0/16", "--subnet=192.170.0.0/16", "test6") 615 assertNwIsAvailable(c, "test6") 616 617 // test network with multiple subnets with valid ipam combinations 618 // also check same subnet across networks when the driver supports it. 619 dockerCmd(c, "network", "create", "-d", dummyNetworkDriver, 620 "--subnet=192.168.0.0/16", "--subnet=192.170.0.0/16", 621 "--gateway=192.168.0.100", "--gateway=192.170.0.100", 622 "--ip-range=192.168.1.0/24", 623 "--aux-address", "a=192.168.1.5", "--aux-address", "b=192.168.1.6", 624 "--aux-address", "c=192.170.1.5", "--aux-address", "d=192.170.1.6", 625 "test7") 626 assertNwIsAvailable(c, "test7") 627 628 // cleanup 629 for i := 1; i < 8; i++ { 630 dockerCmd(c, "network", "rm", fmt.Sprintf("test%d", i)) 631 } 632 } 633 634 func (s *DockerNetworkSuite) TestDockerNetworkCustomIPAM(c *check.C) { 635 testRequires(c, SameHostDaemon) 636 // Create a bridge network using custom ipam driver 637 dockerCmd(c, "network", "create", "--ipam-driver", dummyIPAMDriver, "br0") 638 assertNwIsAvailable(c, "br0") 639 640 // Verify expected network ipam fields are there 641 nr := getNetworkResource(c, "br0") 642 c.Assert(nr.Driver, checker.Equals, "bridge") 643 c.Assert(nr.IPAM.Driver, checker.Equals, dummyIPAMDriver) 644 645 // remove network and exercise remote ipam driver 646 dockerCmd(c, "network", "rm", "br0") 647 assertNwNotAvailable(c, "br0") 648 } 649 650 func (s *DockerNetworkSuite) TestDockerNetworkIPAMOptions(c *check.C) { 651 testRequires(c, SameHostDaemon) 652 // Create a bridge network using custom ipam driver and options 653 dockerCmd(c, "network", "create", "--ipam-driver", dummyIPAMDriver, "--ipam-opt", "opt1=drv1", "--ipam-opt", "opt2=drv2", "br0") 654 assertNwIsAvailable(c, "br0") 655 656 // Verify expected network ipam options 657 nr := getNetworkResource(c, "br0") 658 opts := nr.IPAM.Options 659 c.Assert(opts["opt1"], checker.Equals, "drv1") 660 c.Assert(opts["opt2"], checker.Equals, "drv2") 661 } 662 663 func (s *DockerNetworkSuite) TestDockerNetworkNullIPAMDriver(c *check.C) { 664 testRequires(c, SameHostDaemon) 665 // Create a network with null ipam driver 666 _, _, err := dockerCmdWithError("network", "create", "-d", dummyNetworkDriver, "--ipam-driver", "null", "test000") 667 c.Assert(err, check.IsNil) 668 assertNwIsAvailable(c, "test000") 669 670 // Verify the inspect data contains the default subnet provided by the null 671 // ipam driver and no gateway, as the null ipam driver does not provide one 672 nr := getNetworkResource(c, "test000") 673 c.Assert(nr.IPAM.Driver, checker.Equals, "null") 674 c.Assert(len(nr.IPAM.Config), checker.Equals, 1) 675 c.Assert(nr.IPAM.Config[0].Subnet, checker.Equals, "0.0.0.0/0") 676 c.Assert(nr.IPAM.Config[0].Gateway, checker.Equals, "") 677 } 678 679 func (s *DockerNetworkSuite) TestDockerNetworkInspectDefault(c *check.C) { 680 nr := getNetworkResource(c, "none") 681 c.Assert(nr.Driver, checker.Equals, "null") 682 c.Assert(nr.Scope, checker.Equals, "local") 683 c.Assert(nr.Internal, checker.Equals, false) 684 c.Assert(nr.EnableIPv6, checker.Equals, false) 685 c.Assert(nr.IPAM.Driver, checker.Equals, "default") 686 c.Assert(len(nr.IPAM.Config), checker.Equals, 0) 687 688 nr = getNetworkResource(c, "host") 689 c.Assert(nr.Driver, checker.Equals, "host") 690 c.Assert(nr.Scope, checker.Equals, "local") 691 c.Assert(nr.Internal, checker.Equals, false) 692 c.Assert(nr.EnableIPv6, checker.Equals, false) 693 c.Assert(nr.IPAM.Driver, checker.Equals, "default") 694 c.Assert(len(nr.IPAM.Config), checker.Equals, 0) 695 696 nr = getNetworkResource(c, "bridge") 697 c.Assert(nr.Driver, checker.Equals, "bridge") 698 c.Assert(nr.Scope, checker.Equals, "local") 699 c.Assert(nr.Internal, checker.Equals, false) 700 c.Assert(nr.EnableIPv6, checker.Equals, false) 701 c.Assert(nr.IPAM.Driver, checker.Equals, "default") 702 c.Assert(len(nr.IPAM.Config), checker.Equals, 1) 703 c.Assert(nr.IPAM.Config[0].Subnet, checker.NotNil) 704 c.Assert(nr.IPAM.Config[0].Gateway, checker.NotNil) 705 } 706 707 func (s *DockerNetworkSuite) TestDockerNetworkInspectCustomUnspecified(c *check.C) { 708 // if unspecified, network subnet will be selected from inside preferred pool 709 dockerCmd(c, "network", "create", "test01") 710 assertNwIsAvailable(c, "test01") 711 712 nr := getNetworkResource(c, "test01") 713 c.Assert(nr.Driver, checker.Equals, "bridge") 714 c.Assert(nr.Scope, checker.Equals, "local") 715 c.Assert(nr.Internal, checker.Equals, false) 716 c.Assert(nr.EnableIPv6, checker.Equals, false) 717 c.Assert(nr.IPAM.Driver, checker.Equals, "default") 718 c.Assert(len(nr.IPAM.Config), checker.Equals, 1) 719 c.Assert(nr.IPAM.Config[0].Subnet, checker.NotNil) 720 c.Assert(nr.IPAM.Config[0].Gateway, checker.NotNil) 721 722 dockerCmd(c, "network", "rm", "test01") 723 assertNwNotAvailable(c, "test01") 724 } 725 726 func (s *DockerNetworkSuite) TestDockerNetworkInspectCustomSpecified(c *check.C) { 727 dockerCmd(c, "network", "create", "--driver=bridge", "--ipv6", "--subnet=fd80:24e2:f998:72d6::/64", "--subnet=172.28.0.0/16", "--ip-range=172.28.5.0/24", "--gateway=172.28.5.254", "br0") 728 assertNwIsAvailable(c, "br0") 729 730 nr := getNetworkResource(c, "br0") 731 c.Assert(nr.Driver, checker.Equals, "bridge") 732 c.Assert(nr.Scope, checker.Equals, "local") 733 c.Assert(nr.Internal, checker.Equals, false) 734 c.Assert(nr.EnableIPv6, checker.Equals, true) 735 c.Assert(nr.IPAM.Driver, checker.Equals, "default") 736 c.Assert(len(nr.IPAM.Config), checker.Equals, 2) 737 c.Assert(nr.IPAM.Config[0].Subnet, checker.Equals, "172.28.0.0/16") 738 c.Assert(nr.IPAM.Config[0].IPRange, checker.Equals, "172.28.5.0/24") 739 c.Assert(nr.IPAM.Config[0].Gateway, checker.Equals, "172.28.5.254") 740 c.Assert(nr.Internal, checker.False) 741 dockerCmd(c, "network", "rm", "br0") 742 assertNwNotAvailable(c, "test01") 743 } 744 745 func (s *DockerNetworkSuite) TestDockerNetworkIPAMInvalidCombinations(c *check.C) { 746 // network with ip-range out of subnet range 747 _, _, err := dockerCmdWithError("network", "create", "--subnet=192.168.0.0/16", "--ip-range=192.170.0.0/16", "test") 748 c.Assert(err, check.NotNil) 749 750 // network with multiple gateways for a single subnet 751 _, _, err = dockerCmdWithError("network", "create", "--subnet=192.168.0.0/16", "--gateway=192.168.0.1", "--gateway=192.168.0.2", "test") 752 c.Assert(err, check.NotNil) 753 754 // Multiple overlapping subnets in the same network must fail 755 _, _, err = dockerCmdWithError("network", "create", "--subnet=192.168.0.0/16", "--subnet=192.168.1.0/16", "test") 756 c.Assert(err, check.NotNil) 757 758 // overlapping subnets across networks must fail 759 // create a valid test0 network 760 dockerCmd(c, "network", "create", "--subnet=192.168.0.0/16", "test0") 761 assertNwIsAvailable(c, "test0") 762 // create an overlapping test1 network 763 _, _, err = dockerCmdWithError("network", "create", "--subnet=192.168.128.0/17", "test1") 764 c.Assert(err, check.NotNil) 765 dockerCmd(c, "network", "rm", "test0") 766 assertNwNotAvailable(c, "test0") 767 } 768 769 func (s *DockerNetworkSuite) TestDockerNetworkDriverOptions(c *check.C) { 770 testRequires(c, SameHostDaemon) 771 dockerCmd(c, "network", "create", "-d", dummyNetworkDriver, "-o", "opt1=drv1", "-o", "opt2=drv2", "testopt") 772 assertNwIsAvailable(c, "testopt") 773 gopts := remoteDriverNetworkRequest.Options[netlabel.GenericData] 774 c.Assert(gopts, checker.NotNil) 775 opts, ok := gopts.(map[string]interface{}) 776 c.Assert(ok, checker.Equals, true) 777 c.Assert(opts["opt1"], checker.Equals, "drv1") 778 c.Assert(opts["opt2"], checker.Equals, "drv2") 779 dockerCmd(c, "network", "rm", "testopt") 780 assertNwNotAvailable(c, "testopt") 781 782 } 783 784 func (s *DockerNetworkSuite) TestDockerPluginV2NetworkDriver(c *check.C) { 785 testRequires(c, DaemonIsLinux, IsAmd64, Network) 786 787 var ( 788 npName = "tiborvass/test-docker-netplugin" 789 npTag = "latest" 790 npNameWithTag = npName + ":" + npTag 791 ) 792 _, _, err := dockerCmdWithError("plugin", "install", "--grant-all-permissions", npNameWithTag) 793 c.Assert(err, checker.IsNil) 794 795 out, _, err := dockerCmdWithError("plugin", "ls") 796 c.Assert(err, checker.IsNil) 797 c.Assert(out, checker.Contains, npName) 798 c.Assert(out, checker.Contains, npTag) 799 c.Assert(out, checker.Contains, "true") 800 801 dockerCmd(c, "network", "create", "-d", npNameWithTag, "v2net") 802 assertNwIsAvailable(c, "v2net") 803 dockerCmd(c, "network", "rm", "v2net") 804 assertNwNotAvailable(c, "v2net") 805 806 } 807 808 func (s *DockerDaemonSuite) TestDockerNetworkNoDiscoveryDefaultBridgeNetwork(c *check.C) { 809 testRequires(c, ExecSupport) 810 // On default bridge network built-in service discovery should not happen 811 hostsFile := "/etc/hosts" 812 bridgeName := "external-bridge" 813 bridgeIP := "192.169.255.254/24" 814 createInterface(c, "bridge", bridgeName, bridgeIP) 815 defer deleteInterface(c, bridgeName) 816 817 s.d.StartWithBusybox(c, "--bridge", bridgeName) 818 defer s.d.Restart(c) 819 820 // run two containers and store first container's etc/hosts content 821 out, err := s.d.Cmd("run", "-d", "busybox", "top") 822 c.Assert(err, check.IsNil) 823 cid1 := strings.TrimSpace(out) 824 defer s.d.Cmd("stop", cid1) 825 826 hosts, err := s.d.Cmd("exec", cid1, "cat", hostsFile) 827 c.Assert(err, checker.IsNil) 828 829 out, err = s.d.Cmd("run", "-d", "--name", "container2", "busybox", "top") 830 c.Assert(err, check.IsNil) 831 cid2 := strings.TrimSpace(out) 832 833 // verify first container's etc/hosts file has not changed after spawning the second named container 834 hostsPost, err := s.d.Cmd("exec", cid1, "cat", hostsFile) 835 c.Assert(err, checker.IsNil) 836 c.Assert(string(hosts), checker.Equals, string(hostsPost), 837 check.Commentf("Unexpected %s change on second container creation", hostsFile)) 838 839 // stop container 2 and verify first container's etc/hosts has not changed 840 _, err = s.d.Cmd("stop", cid2) 841 c.Assert(err, check.IsNil) 842 843 hostsPost, err = s.d.Cmd("exec", cid1, "cat", hostsFile) 844 c.Assert(err, checker.IsNil) 845 c.Assert(string(hosts), checker.Equals, string(hostsPost), 846 check.Commentf("Unexpected %s change on second container creation", hostsFile)) 847 848 // but discovery is on when connecting to non default bridge network 849 network := "anotherbridge" 850 out, err = s.d.Cmd("network", "create", network) 851 c.Assert(err, check.IsNil, check.Commentf(out)) 852 defer s.d.Cmd("network", "rm", network) 853 854 out, err = s.d.Cmd("network", "connect", network, cid1) 855 c.Assert(err, check.IsNil, check.Commentf(out)) 856 857 hosts, err = s.d.Cmd("exec", cid1, "cat", hostsFile) 858 c.Assert(err, checker.IsNil) 859 860 hostsPost, err = s.d.Cmd("exec", cid1, "cat", hostsFile) 861 c.Assert(err, checker.IsNil) 862 c.Assert(string(hosts), checker.Equals, string(hostsPost), 863 check.Commentf("Unexpected %s change on second network connection", hostsFile)) 864 } 865 866 func (s *DockerNetworkSuite) TestDockerNetworkAnonymousEndpoint(c *check.C) { 867 testRequires(c, ExecSupport, NotArm) 868 hostsFile := "/etc/hosts" 869 cstmBridgeNw := "custom-bridge-nw" 870 cstmBridgeNw1 := "custom-bridge-nw1" 871 872 dockerCmd(c, "network", "create", "-d", "bridge", cstmBridgeNw) 873 assertNwIsAvailable(c, cstmBridgeNw) 874 875 // run two anonymous containers and store their etc/hosts content 876 out, _ := dockerCmd(c, "run", "-d", "--net", cstmBridgeNw, "busybox", "top") 877 cid1 := strings.TrimSpace(out) 878 879 hosts1 := readContainerFileWithExec(c, cid1, hostsFile) 880 881 out, _ = dockerCmd(c, "run", "-d", "--net", cstmBridgeNw, "busybox", "top") 882 cid2 := strings.TrimSpace(out) 883 884 hosts2 := readContainerFileWithExec(c, cid2, hostsFile) 885 886 // verify first container etc/hosts file has not changed 887 hosts1post := readContainerFileWithExec(c, cid1, hostsFile) 888 c.Assert(string(hosts1), checker.Equals, string(hosts1post), 889 check.Commentf("Unexpected %s change on anonymous container creation", hostsFile)) 890 891 // Connect the 2nd container to a new network and verify the 892 // first container /etc/hosts file still hasn't changed. 893 dockerCmd(c, "network", "create", "-d", "bridge", cstmBridgeNw1) 894 assertNwIsAvailable(c, cstmBridgeNw1) 895 896 dockerCmd(c, "network", "connect", cstmBridgeNw1, cid2) 897 898 hosts2 = readContainerFileWithExec(c, cid2, hostsFile) 899 hosts1post = readContainerFileWithExec(c, cid1, hostsFile) 900 c.Assert(string(hosts1), checker.Equals, string(hosts1post), 901 check.Commentf("Unexpected %s change on container connect", hostsFile)) 902 903 // start a named container 904 cName := "AnyName" 905 out, _ = dockerCmd(c, "run", "-d", "--net", cstmBridgeNw, "--name", cName, "busybox", "top") 906 cid3 := strings.TrimSpace(out) 907 908 // verify that container 1 and 2 can ping the named container 909 dockerCmd(c, "exec", cid1, "ping", "-c", "1", cName) 910 dockerCmd(c, "exec", cid2, "ping", "-c", "1", cName) 911 912 // Stop named container and verify first two containers' etc/hosts file hasn't changed 913 dockerCmd(c, "stop", cid3) 914 hosts1post = readContainerFileWithExec(c, cid1, hostsFile) 915 c.Assert(string(hosts1), checker.Equals, string(hosts1post), 916 check.Commentf("Unexpected %s change on name container creation", hostsFile)) 917 918 hosts2post := readContainerFileWithExec(c, cid2, hostsFile) 919 c.Assert(string(hosts2), checker.Equals, string(hosts2post), 920 check.Commentf("Unexpected %s change on name container creation", hostsFile)) 921 922 // verify that container 1 and 2 can't ping the named container now 923 _, _, err := dockerCmdWithError("exec", cid1, "ping", "-c", "1", cName) 924 c.Assert(err, check.NotNil) 925 _, _, err = dockerCmdWithError("exec", cid2, "ping", "-c", "1", cName) 926 c.Assert(err, check.NotNil) 927 } 928 929 func (s *DockerNetworkSuite) TestDockerNetworkLinkOnDefaultNetworkOnly(c *check.C) { 930 // Legacy Link feature must work only on default network, and not across networks 931 cnt1 := "container1" 932 cnt2 := "container2" 933 network := "anotherbridge" 934 935 // Run first container on default network 936 dockerCmd(c, "run", "-d", "--name", cnt1, "busybox", "top") 937 938 // Create another network and run the second container on it 939 dockerCmd(c, "network", "create", network) 940 assertNwIsAvailable(c, network) 941 dockerCmd(c, "run", "-d", "--net", network, "--name", cnt2, "busybox", "top") 942 943 // Try launching a container on default network, linking to the first container. Must succeed 944 dockerCmd(c, "run", "-d", "--link", fmt.Sprintf("%s:%s", cnt1, cnt1), "busybox", "top") 945 946 // Try launching a container on default network, linking to the second container. Must fail 947 _, _, err := dockerCmdWithError("run", "-d", "--link", fmt.Sprintf("%s:%s", cnt2, cnt2), "busybox", "top") 948 c.Assert(err, checker.NotNil) 949 950 // Connect second container to default network. Now a container on default network can link to it 951 dockerCmd(c, "network", "connect", "bridge", cnt2) 952 dockerCmd(c, "run", "-d", "--link", fmt.Sprintf("%s:%s", cnt2, cnt2), "busybox", "top") 953 } 954 955 func (s *DockerNetworkSuite) TestDockerNetworkOverlayPortMapping(c *check.C) { 956 testRequires(c, SameHostDaemon) 957 // Verify exposed ports are present in ps output when running a container on 958 // a network managed by a driver which does not provide the default gateway 959 // for the container 960 nwn := "ov" 961 ctn := "bb" 962 port1 := 80 963 port2 := 443 964 expose1 := fmt.Sprintf("--expose=%d", port1) 965 expose2 := fmt.Sprintf("--expose=%d", port2) 966 967 dockerCmd(c, "network", "create", "-d", dummyNetworkDriver, nwn) 968 assertNwIsAvailable(c, nwn) 969 970 dockerCmd(c, "run", "-d", "--net", nwn, "--name", ctn, expose1, expose2, "busybox", "top") 971 972 // Check docker ps o/p for last created container reports the unpublished ports 973 unpPort1 := fmt.Sprintf("%d/tcp", port1) 974 unpPort2 := fmt.Sprintf("%d/tcp", port2) 975 out, _ := dockerCmd(c, "ps", "-n=1") 976 // Missing unpublished ports in docker ps output 977 c.Assert(out, checker.Contains, unpPort1) 978 // Missing unpublished ports in docker ps output 979 c.Assert(out, checker.Contains, unpPort2) 980 } 981 982 func (s *DockerNetworkSuite) TestDockerNetworkDriverUngracefulRestart(c *check.C) { 983 testRequires(c, DaemonIsLinux, NotUserNamespace, SameHostDaemon) 984 dnd := "dnd" 985 did := "did" 986 987 mux := http.NewServeMux() 988 server := httptest.NewServer(mux) 989 setupRemoteNetworkDrivers(c, mux, server.URL, dnd, did) 990 991 s.d.StartWithBusybox(c) 992 _, err := s.d.Cmd("network", "create", "-d", dnd, "--subnet", "1.1.1.0/24", "net1") 993 c.Assert(err, checker.IsNil) 994 995 _, err = s.d.Cmd("run", "-itd", "--net", "net1", "--name", "foo", "--ip", "1.1.1.10", "busybox", "sh") 996 c.Assert(err, checker.IsNil) 997 998 // Kill daemon and restart 999 c.Assert(s.d.Kill(), checker.IsNil) 1000 1001 server.Close() 1002 1003 startTime := time.Now().Unix() 1004 s.d.Restart(c) 1005 lapse := time.Now().Unix() - startTime 1006 if lapse > 60 { 1007 // In normal scenarios, daemon restart takes ~1 second. 1008 // Plugin retry mechanism can delay the daemon start. systemd may not like it. 1009 // Avoid accessing plugins during daemon bootup 1010 c.Logf("daemon restart took too long : %d seconds", lapse) 1011 } 1012 1013 // Restart the custom dummy plugin 1014 mux = http.NewServeMux() 1015 server = httptest.NewServer(mux) 1016 setupRemoteNetworkDrivers(c, mux, server.URL, dnd, did) 1017 1018 // trying to reuse the same ip must succeed 1019 _, err = s.d.Cmd("run", "-itd", "--net", "net1", "--name", "bar", "--ip", "1.1.1.10", "busybox", "sh") 1020 c.Assert(err, checker.IsNil) 1021 } 1022 1023 func (s *DockerNetworkSuite) TestDockerNetworkMacInspect(c *check.C) { 1024 testRequires(c, SameHostDaemon) 1025 // Verify endpoint MAC address is correctly populated in container's network settings 1026 nwn := "ov" 1027 ctn := "bb" 1028 1029 dockerCmd(c, "network", "create", "-d", dummyNetworkDriver, nwn) 1030 assertNwIsAvailable(c, nwn) 1031 1032 dockerCmd(c, "run", "-d", "--net", nwn, "--name", ctn, "busybox", "top") 1033 1034 mac := inspectField(c, ctn, "NetworkSettings.Networks."+nwn+".MacAddress") 1035 c.Assert(mac, checker.Equals, "a0:b1:c2:d3:e4:f5") 1036 } 1037 1038 func (s *DockerSuite) TestInspectAPIMultipleNetworks(c *check.C) { 1039 dockerCmd(c, "network", "create", "mybridge1") 1040 dockerCmd(c, "network", "create", "mybridge2") 1041 out, _ := dockerCmd(c, "run", "-d", "busybox", "top") 1042 id := strings.TrimSpace(out) 1043 c.Assert(waitRun(id), check.IsNil) 1044 1045 dockerCmd(c, "network", "connect", "mybridge1", id) 1046 dockerCmd(c, "network", "connect", "mybridge2", id) 1047 1048 body := getInspectBody(c, "v1.20", id) 1049 var inspect120 v1p20.ContainerJSON 1050 err := json.Unmarshal(body, &inspect120) 1051 c.Assert(err, checker.IsNil) 1052 1053 versionedIP := inspect120.NetworkSettings.IPAddress 1054 1055 body = getInspectBody(c, "v1.21", id) 1056 var inspect121 types.ContainerJSON 1057 err = json.Unmarshal(body, &inspect121) 1058 c.Assert(err, checker.IsNil) 1059 c.Assert(inspect121.NetworkSettings.Networks, checker.HasLen, 3) 1060 1061 bridge := inspect121.NetworkSettings.Networks["bridge"] 1062 c.Assert(bridge.IPAddress, checker.Equals, versionedIP) 1063 c.Assert(bridge.IPAddress, checker.Equals, inspect121.NetworkSettings.IPAddress) 1064 } 1065 1066 func connectContainerToNetworks(c *check.C, d *daemon.Daemon, cName string, nws []string) { 1067 // Run a container on the default network 1068 out, err := d.Cmd("run", "-d", "--name", cName, "busybox", "top") 1069 c.Assert(err, checker.IsNil, check.Commentf(out)) 1070 1071 // Attach the container to other networks 1072 for _, nw := range nws { 1073 out, err = d.Cmd("network", "create", nw) 1074 c.Assert(err, checker.IsNil, check.Commentf(out)) 1075 out, err = d.Cmd("network", "connect", nw, cName) 1076 c.Assert(err, checker.IsNil, check.Commentf(out)) 1077 } 1078 } 1079 1080 func verifyContainerIsConnectedToNetworks(c *check.C, d *daemon.Daemon, cName string, nws []string) { 1081 // Verify container is connected to all the networks 1082 for _, nw := range nws { 1083 out, err := d.Cmd("inspect", "-f", fmt.Sprintf("{{.NetworkSettings.Networks.%s}}", nw), cName) 1084 c.Assert(err, checker.IsNil, check.Commentf(out)) 1085 c.Assert(out, checker.Not(checker.Equals), "<no value>\n") 1086 } 1087 } 1088 1089 func (s *DockerNetworkSuite) TestDockerNetworkMultipleNetworksGracefulDaemonRestart(c *check.C) { 1090 testRequires(c, SameHostDaemon) 1091 cName := "bb" 1092 nwList := []string{"nw1", "nw2", "nw3"} 1093 1094 s.d.StartWithBusybox(c) 1095 1096 connectContainerToNetworks(c, s.d, cName, nwList) 1097 verifyContainerIsConnectedToNetworks(c, s.d, cName, nwList) 1098 1099 // Reload daemon 1100 s.d.Restart(c) 1101 1102 _, err := s.d.Cmd("start", cName) 1103 c.Assert(err, checker.IsNil) 1104 1105 verifyContainerIsConnectedToNetworks(c, s.d, cName, nwList) 1106 } 1107 1108 func (s *DockerNetworkSuite) TestDockerNetworkMultipleNetworksUngracefulDaemonRestart(c *check.C) { 1109 testRequires(c, SameHostDaemon) 1110 cName := "cc" 1111 nwList := []string{"nw1", "nw2", "nw3"} 1112 1113 s.d.StartWithBusybox(c) 1114 1115 connectContainerToNetworks(c, s.d, cName, nwList) 1116 verifyContainerIsConnectedToNetworks(c, s.d, cName, nwList) 1117 1118 // Kill daemon and restart 1119 c.Assert(s.d.Kill(), checker.IsNil) 1120 s.d.Restart(c) 1121 1122 // Restart container 1123 _, err := s.d.Cmd("start", cName) 1124 c.Assert(err, checker.IsNil) 1125 1126 verifyContainerIsConnectedToNetworks(c, s.d, cName, nwList) 1127 } 1128 1129 func (s *DockerNetworkSuite) TestDockerNetworkRunNetByID(c *check.C) { 1130 out, _ := dockerCmd(c, "network", "create", "one") 1131 containerOut, _, err := dockerCmdWithError("run", "-d", "--net", strings.TrimSpace(out), "busybox", "top") 1132 c.Assert(err, checker.IsNil, check.Commentf(containerOut)) 1133 } 1134 1135 func (s *DockerNetworkSuite) TestDockerNetworkHostModeUngracefulDaemonRestart(c *check.C) { 1136 testRequires(c, DaemonIsLinux, NotUserNamespace, SameHostDaemon) 1137 s.d.StartWithBusybox(c) 1138 1139 // Run a few containers on host network 1140 for i := 0; i < 10; i++ { 1141 cName := fmt.Sprintf("hostc-%d", i) 1142 out, err := s.d.Cmd("run", "-d", "--name", cName, "--net=host", "--restart=always", "busybox", "top") 1143 c.Assert(err, checker.IsNil, check.Commentf(out)) 1144 1145 // verify container has finished starting before killing daemon 1146 err = s.d.WaitRun(cName) 1147 c.Assert(err, checker.IsNil) 1148 } 1149 1150 // Kill daemon ungracefully and restart 1151 c.Assert(s.d.Kill(), checker.IsNil) 1152 s.d.Restart(c) 1153 1154 // make sure all the containers are up and running 1155 for i := 0; i < 10; i++ { 1156 err := s.d.WaitRun(fmt.Sprintf("hostc-%d", i)) 1157 c.Assert(err, checker.IsNil) 1158 } 1159 } 1160 1161 func (s *DockerNetworkSuite) TestDockerNetworkConnectToHostFromOtherNetwork(c *check.C) { 1162 dockerCmd(c, "run", "-d", "--name", "container1", "busybox", "top") 1163 c.Assert(waitRun("container1"), check.IsNil) 1164 dockerCmd(c, "network", "disconnect", "bridge", "container1") 1165 out, _, err := dockerCmdWithError("network", "connect", "host", "container1") 1166 c.Assert(err, checker.NotNil, check.Commentf(out)) 1167 c.Assert(out, checker.Contains, runconfig.ErrConflictHostNetwork.Error()) 1168 } 1169 1170 func (s *DockerNetworkSuite) TestDockerNetworkDisconnectFromHost(c *check.C) { 1171 dockerCmd(c, "run", "-d", "--name", "container1", "--net=host", "busybox", "top") 1172 c.Assert(waitRun("container1"), check.IsNil) 1173 out, _, err := dockerCmdWithError("network", "disconnect", "host", "container1") 1174 c.Assert(err, checker.NotNil, check.Commentf("Should err out disconnect from host")) 1175 c.Assert(out, checker.Contains, runconfig.ErrConflictHostNetwork.Error()) 1176 } 1177 1178 func (s *DockerNetworkSuite) TestDockerNetworkConnectWithPortMapping(c *check.C) { 1179 testRequires(c, NotArm) 1180 dockerCmd(c, "network", "create", "test1") 1181 dockerCmd(c, "run", "-d", "--name", "c1", "-p", "5000:5000", "busybox", "top") 1182 c.Assert(waitRun("c1"), check.IsNil) 1183 dockerCmd(c, "network", "connect", "test1", "c1") 1184 } 1185 1186 func verifyPortMap(c *check.C, container, port, originalMapping string, mustBeEqual bool) { 1187 chk := checker.Equals 1188 if !mustBeEqual { 1189 chk = checker.Not(checker.Equals) 1190 } 1191 currentMapping, _ := dockerCmd(c, "port", container, port) 1192 c.Assert(currentMapping, chk, originalMapping) 1193 } 1194 1195 func (s *DockerNetworkSuite) TestDockerNetworkConnectDisconnectWithPortMapping(c *check.C) { 1196 // Connect and disconnect a container with explicit and non-explicit 1197 // host port mapping to/from networks which do cause and do not cause 1198 // the container default gateway to change, and verify docker port cmd 1199 // returns congruent information 1200 testRequires(c, NotArm) 1201 cnt := "c1" 1202 dockerCmd(c, "network", "create", "aaa") 1203 dockerCmd(c, "network", "create", "ccc") 1204 1205 dockerCmd(c, "run", "-d", "--name", cnt, "-p", "9000:90", "-p", "70", "busybox", "top") 1206 c.Assert(waitRun(cnt), check.IsNil) 1207 curPortMap, _ := dockerCmd(c, "port", cnt, "70") 1208 curExplPortMap, _ := dockerCmd(c, "port", cnt, "90") 1209 1210 // Connect to a network which causes the container's default gw switch 1211 dockerCmd(c, "network", "connect", "aaa", cnt) 1212 verifyPortMap(c, cnt, "70", curPortMap, false) 1213 verifyPortMap(c, cnt, "90", curExplPortMap, true) 1214 1215 // Read current mapping 1216 curPortMap, _ = dockerCmd(c, "port", cnt, "70") 1217 1218 // Disconnect from a network which causes the container's default gw switch 1219 dockerCmd(c, "network", "disconnect", "aaa", cnt) 1220 verifyPortMap(c, cnt, "70", curPortMap, false) 1221 verifyPortMap(c, cnt, "90", curExplPortMap, true) 1222 1223 // Read current mapping 1224 curPortMap, _ = dockerCmd(c, "port", cnt, "70") 1225 1226 // Connect to a network which does not cause the container's default gw switch 1227 dockerCmd(c, "network", "connect", "ccc", cnt) 1228 verifyPortMap(c, cnt, "70", curPortMap, true) 1229 verifyPortMap(c, cnt, "90", curExplPortMap, true) 1230 } 1231 1232 func (s *DockerNetworkSuite) TestDockerNetworkConnectWithMac(c *check.C) { 1233 macAddress := "02:42:ac:11:00:02" 1234 dockerCmd(c, "network", "create", "mynetwork") 1235 dockerCmd(c, "run", "--name=test", "-d", "--mac-address", macAddress, "busybox", "top") 1236 c.Assert(waitRun("test"), check.IsNil) 1237 mac1 := inspectField(c, "test", "NetworkSettings.Networks.bridge.MacAddress") 1238 c.Assert(strings.TrimSpace(mac1), checker.Equals, macAddress) 1239 dockerCmd(c, "network", "connect", "mynetwork", "test") 1240 mac2 := inspectField(c, "test", "NetworkSettings.Networks.mynetwork.MacAddress") 1241 c.Assert(strings.TrimSpace(mac2), checker.Not(checker.Equals), strings.TrimSpace(mac1)) 1242 } 1243 1244 func (s *DockerNetworkSuite) TestDockerNetworkInspectCreatedContainer(c *check.C) { 1245 dockerCmd(c, "create", "--name", "test", "busybox") 1246 networks := inspectField(c, "test", "NetworkSettings.Networks") 1247 c.Assert(networks, checker.Contains, "bridge", check.Commentf("Should return 'bridge' network")) 1248 } 1249 1250 func (s *DockerNetworkSuite) TestDockerNetworkRestartWithMultipleNetworks(c *check.C) { 1251 dockerCmd(c, "network", "create", "test") 1252 dockerCmd(c, "run", "--name=foo", "-d", "busybox", "top") 1253 c.Assert(waitRun("foo"), checker.IsNil) 1254 dockerCmd(c, "network", "connect", "test", "foo") 1255 dockerCmd(c, "restart", "foo") 1256 networks := inspectField(c, "foo", "NetworkSettings.Networks") 1257 c.Assert(networks, checker.Contains, "bridge", check.Commentf("Should contain 'bridge' network")) 1258 c.Assert(networks, checker.Contains, "test", check.Commentf("Should contain 'test' network")) 1259 } 1260 1261 func (s *DockerNetworkSuite) TestDockerNetworkConnectDisconnectToStoppedContainer(c *check.C) { 1262 testRequires(c, SameHostDaemon) 1263 dockerCmd(c, "network", "create", "test") 1264 dockerCmd(c, "create", "--name=foo", "busybox", "top") 1265 dockerCmd(c, "network", "connect", "test", "foo") 1266 networks := inspectField(c, "foo", "NetworkSettings.Networks") 1267 c.Assert(networks, checker.Contains, "test", check.Commentf("Should contain 'test' network")) 1268 1269 // Restart docker daemon to test the config has persisted to disk 1270 s.d.Restart(c) 1271 networks = inspectField(c, "foo", "NetworkSettings.Networks") 1272 c.Assert(networks, checker.Contains, "test", check.Commentf("Should contain 'test' network")) 1273 1274 // start the container and test if we can ping it from another container in the same network 1275 dockerCmd(c, "start", "foo") 1276 c.Assert(waitRun("foo"), checker.IsNil) 1277 ip := inspectField(c, "foo", "NetworkSettings.Networks.test.IPAddress") 1278 ip = strings.TrimSpace(ip) 1279 dockerCmd(c, "run", "--net=test", "busybox", "sh", "-c", fmt.Sprintf("ping -c 1 %s", ip)) 1280 1281 dockerCmd(c, "stop", "foo") 1282 1283 // Test disconnect 1284 dockerCmd(c, "network", "disconnect", "test", "foo") 1285 networks = inspectField(c, "foo", "NetworkSettings.Networks") 1286 c.Assert(networks, checker.Not(checker.Contains), "test", check.Commentf("Should not contain 'test' network")) 1287 1288 // Restart docker daemon to test the config has persisted to disk 1289 s.d.Restart(c) 1290 networks = inspectField(c, "foo", "NetworkSettings.Networks") 1291 c.Assert(networks, checker.Not(checker.Contains), "test", check.Commentf("Should not contain 'test' network")) 1292 1293 } 1294 1295 func (s *DockerNetworkSuite) TestDockerNetworkDisconnectContainerNonexistingNetwork(c *check.C) { 1296 dockerCmd(c, "network", "create", "test") 1297 dockerCmd(c, "run", "--net=test", "-d", "--name=foo", "busybox", "top") 1298 networks := inspectField(c, "foo", "NetworkSettings.Networks") 1299 c.Assert(networks, checker.Contains, "test", check.Commentf("Should contain 'test' network")) 1300 1301 // Stop container and remove network 1302 dockerCmd(c, "stop", "foo") 1303 dockerCmd(c, "network", "rm", "test") 1304 1305 // Test disconnecting stopped container from nonexisting network 1306 dockerCmd(c, "network", "disconnect", "-f", "test", "foo") 1307 networks = inspectField(c, "foo", "NetworkSettings.Networks") 1308 c.Assert(networks, checker.Not(checker.Contains), "test", check.Commentf("Should not contain 'test' network")) 1309 } 1310 1311 func (s *DockerNetworkSuite) TestDockerNetworkConnectPreferredIP(c *check.C) { 1312 // create two networks 1313 dockerCmd(c, "network", "create", "--ipv6", "--subnet=172.28.0.0/16", "--subnet=2001:db8:1234::/64", "n0") 1314 assertNwIsAvailable(c, "n0") 1315 1316 dockerCmd(c, "network", "create", "--ipv6", "--subnet=172.30.0.0/16", "--ip-range=172.30.5.0/24", "--subnet=2001:db8:abcd::/64", "--ip-range=2001:db8:abcd::/80", "n1") 1317 assertNwIsAvailable(c, "n1") 1318 1319 // run a container on first network specifying the ip addresses 1320 dockerCmd(c, "run", "-d", "--name", "c0", "--net=n0", "--ip", "172.28.99.88", "--ip6", "2001:db8:1234::9988", "busybox", "top") 1321 c.Assert(waitRun("c0"), check.IsNil) 1322 verifyIPAddressConfig(c, "c0", "n0", "172.28.99.88", "2001:db8:1234::9988") 1323 verifyIPAddresses(c, "c0", "n0", "172.28.99.88", "2001:db8:1234::9988") 1324 1325 // connect the container to the second network specifying an ip addresses 1326 dockerCmd(c, "network", "connect", "--ip", "172.30.55.44", "--ip6", "2001:db8:abcd::5544", "n1", "c0") 1327 verifyIPAddressConfig(c, "c0", "n1", "172.30.55.44", "2001:db8:abcd::5544") 1328 verifyIPAddresses(c, "c0", "n1", "172.30.55.44", "2001:db8:abcd::5544") 1329 1330 // Stop and restart the container 1331 dockerCmd(c, "stop", "c0") 1332 dockerCmd(c, "start", "c0") 1333 1334 // verify requested addresses are applied and configs are still there 1335 verifyIPAddressConfig(c, "c0", "n0", "172.28.99.88", "2001:db8:1234::9988") 1336 verifyIPAddresses(c, "c0", "n0", "172.28.99.88", "2001:db8:1234::9988") 1337 verifyIPAddressConfig(c, "c0", "n1", "172.30.55.44", "2001:db8:abcd::5544") 1338 verifyIPAddresses(c, "c0", "n1", "172.30.55.44", "2001:db8:abcd::5544") 1339 1340 // Still it should fail to connect to the default network with a specified IP (whatever ip) 1341 out, _, err := dockerCmdWithError("network", "connect", "--ip", "172.21.55.44", "bridge", "c0") 1342 c.Assert(err, checker.NotNil, check.Commentf("out: %s", out)) 1343 c.Assert(out, checker.Contains, runconfig.ErrUnsupportedNetworkAndIP.Error()) 1344 1345 } 1346 1347 func (s *DockerNetworkSuite) TestDockerNetworkConnectPreferredIPStoppedContainer(c *check.C) { 1348 // create a container 1349 dockerCmd(c, "create", "--name", "c0", "busybox", "top") 1350 1351 // create a network 1352 dockerCmd(c, "network", "create", "--ipv6", "--subnet=172.30.0.0/16", "--subnet=2001:db8:abcd::/64", "n0") 1353 assertNwIsAvailable(c, "n0") 1354 1355 // connect the container to the network specifying an ip addresses 1356 dockerCmd(c, "network", "connect", "--ip", "172.30.55.44", "--ip6", "2001:db8:abcd::5544", "n0", "c0") 1357 verifyIPAddressConfig(c, "c0", "n0", "172.30.55.44", "2001:db8:abcd::5544") 1358 1359 // start the container, verify config has not changed and ip addresses are assigned 1360 dockerCmd(c, "start", "c0") 1361 c.Assert(waitRun("c0"), check.IsNil) 1362 verifyIPAddressConfig(c, "c0", "n0", "172.30.55.44", "2001:db8:abcd::5544") 1363 verifyIPAddresses(c, "c0", "n0", "172.30.55.44", "2001:db8:abcd::5544") 1364 1365 // stop the container and check ip config has not changed 1366 dockerCmd(c, "stop", "c0") 1367 verifyIPAddressConfig(c, "c0", "n0", "172.30.55.44", "2001:db8:abcd::5544") 1368 } 1369 1370 func (s *DockerNetworkSuite) TestDockerNetworkUnsupportedRequiredIP(c *check.C) { 1371 // requested IP is not supported on predefined networks 1372 for _, mode := range []string{"none", "host", "bridge", "default"} { 1373 checkUnsupportedNetworkAndIP(c, mode) 1374 } 1375 1376 // requested IP is not supported on networks with no user defined subnets 1377 dockerCmd(c, "network", "create", "n0") 1378 assertNwIsAvailable(c, "n0") 1379 1380 out, _, err := dockerCmdWithError("run", "-d", "--ip", "172.28.99.88", "--net", "n0", "busybox", "top") 1381 c.Assert(err, checker.NotNil, check.Commentf("out: %s", out)) 1382 c.Assert(out, checker.Contains, runconfig.ErrUnsupportedNetworkNoSubnetAndIP.Error()) 1383 1384 out, _, err = dockerCmdWithError("run", "-d", "--ip6", "2001:db8:1234::9988", "--net", "n0", "busybox", "top") 1385 c.Assert(err, checker.NotNil, check.Commentf("out: %s", out)) 1386 c.Assert(out, checker.Contains, runconfig.ErrUnsupportedNetworkNoSubnetAndIP.Error()) 1387 1388 dockerCmd(c, "network", "rm", "n0") 1389 assertNwNotAvailable(c, "n0") 1390 } 1391 1392 func checkUnsupportedNetworkAndIP(c *check.C, nwMode string) { 1393 out, _, err := dockerCmdWithError("run", "-d", "--net", nwMode, "--ip", "172.28.99.88", "--ip6", "2001:db8:1234::9988", "busybox", "top") 1394 c.Assert(err, checker.NotNil, check.Commentf("out: %s", out)) 1395 c.Assert(out, checker.Contains, runconfig.ErrUnsupportedNetworkAndIP.Error()) 1396 } 1397 1398 func verifyIPAddressConfig(c *check.C, cName, nwname, ipv4, ipv6 string) { 1399 if ipv4 != "" { 1400 out := inspectField(c, cName, fmt.Sprintf("NetworkSettings.Networks.%s.IPAMConfig.IPv4Address", nwname)) 1401 c.Assert(strings.TrimSpace(out), check.Equals, ipv4) 1402 } 1403 1404 if ipv6 != "" { 1405 out := inspectField(c, cName, fmt.Sprintf("NetworkSettings.Networks.%s.IPAMConfig.IPv6Address", nwname)) 1406 c.Assert(strings.TrimSpace(out), check.Equals, ipv6) 1407 } 1408 } 1409 1410 func verifyIPAddresses(c *check.C, cName, nwname, ipv4, ipv6 string) { 1411 out := inspectField(c, cName, fmt.Sprintf("NetworkSettings.Networks.%s.IPAddress", nwname)) 1412 c.Assert(strings.TrimSpace(out), check.Equals, ipv4) 1413 1414 out = inspectField(c, cName, fmt.Sprintf("NetworkSettings.Networks.%s.GlobalIPv6Address", nwname)) 1415 c.Assert(strings.TrimSpace(out), check.Equals, ipv6) 1416 } 1417 1418 func (s *DockerNetworkSuite) TestDockerNetworkConnectLinkLocalIP(c *check.C) { 1419 // create one test network 1420 dockerCmd(c, "network", "create", "--ipv6", "--subnet=2001:db8:1234::/64", "n0") 1421 assertNwIsAvailable(c, "n0") 1422 1423 // run a container with incorrect link-local address 1424 _, _, err := dockerCmdWithError("run", "--link-local-ip", "169.253.5.5", "busybox", "top") 1425 c.Assert(err, check.NotNil) 1426 _, _, err = dockerCmdWithError("run", "--link-local-ip", "2001:db8::89", "busybox", "top") 1427 c.Assert(err, check.NotNil) 1428 1429 // run two containers with link-local ip on the test network 1430 dockerCmd(c, "run", "-d", "--name", "c0", "--net=n0", "--link-local-ip", "169.254.7.7", "--link-local-ip", "fe80::254:77", "busybox", "top") 1431 c.Assert(waitRun("c0"), check.IsNil) 1432 dockerCmd(c, "run", "-d", "--name", "c1", "--net=n0", "--link-local-ip", "169.254.8.8", "--link-local-ip", "fe80::254:88", "busybox", "top") 1433 c.Assert(waitRun("c1"), check.IsNil) 1434 1435 // run a container on the default network and connect it to the test network specifying a link-local address 1436 dockerCmd(c, "run", "-d", "--name", "c2", "busybox", "top") 1437 c.Assert(waitRun("c2"), check.IsNil) 1438 dockerCmd(c, "network", "connect", "--link-local-ip", "169.254.9.9", "n0", "c2") 1439 1440 // verify the three containers can ping each other via the link-local addresses 1441 _, _, err = dockerCmdWithError("exec", "c0", "ping", "-c", "1", "169.254.8.8") 1442 c.Assert(err, check.IsNil) 1443 _, _, err = dockerCmdWithError("exec", "c1", "ping", "-c", "1", "169.254.9.9") 1444 c.Assert(err, check.IsNil) 1445 _, _, err = dockerCmdWithError("exec", "c2", "ping", "-c", "1", "169.254.7.7") 1446 c.Assert(err, check.IsNil) 1447 1448 // Stop and restart the three containers 1449 dockerCmd(c, "stop", "c0") 1450 dockerCmd(c, "stop", "c1") 1451 dockerCmd(c, "stop", "c2") 1452 dockerCmd(c, "start", "c0") 1453 dockerCmd(c, "start", "c1") 1454 dockerCmd(c, "start", "c2") 1455 1456 // verify the ping again 1457 _, _, err = dockerCmdWithError("exec", "c0", "ping", "-c", "1", "169.254.8.8") 1458 c.Assert(err, check.IsNil) 1459 _, _, err = dockerCmdWithError("exec", "c1", "ping", "-c", "1", "169.254.9.9") 1460 c.Assert(err, check.IsNil) 1461 _, _, err = dockerCmdWithError("exec", "c2", "ping", "-c", "1", "169.254.7.7") 1462 c.Assert(err, check.IsNil) 1463 } 1464 1465 func (s *DockerSuite) TestUserDefinedNetworkConnectDisconnectLink(c *check.C) { 1466 testRequires(c, DaemonIsLinux, NotUserNamespace, NotArm) 1467 dockerCmd(c, "network", "create", "-d", "bridge", "foo1") 1468 dockerCmd(c, "network", "create", "-d", "bridge", "foo2") 1469 1470 dockerCmd(c, "run", "-d", "--net=foo1", "--name=first", "busybox", "top") 1471 c.Assert(waitRun("first"), check.IsNil) 1472 1473 // run a container in a user-defined network with a link for an existing container 1474 // and a link for a container that doesn't exist 1475 dockerCmd(c, "run", "-d", "--net=foo1", "--name=second", "--link=first:FirstInFoo1", 1476 "--link=third:bar", "busybox", "top") 1477 c.Assert(waitRun("second"), check.IsNil) 1478 1479 // ping to first and its alias FirstInFoo1 must succeed 1480 _, _, err := dockerCmdWithError("exec", "second", "ping", "-c", "1", "first") 1481 c.Assert(err, check.IsNil) 1482 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "FirstInFoo1") 1483 c.Assert(err, check.IsNil) 1484 1485 // connect first container to foo2 network 1486 dockerCmd(c, "network", "connect", "foo2", "first") 1487 // connect second container to foo2 network with a different alias for first container 1488 dockerCmd(c, "network", "connect", "--link=first:FirstInFoo2", "foo2", "second") 1489 1490 // ping the new alias in network foo2 1491 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "FirstInFoo2") 1492 c.Assert(err, check.IsNil) 1493 1494 // disconnect first container from foo1 network 1495 dockerCmd(c, "network", "disconnect", "foo1", "first") 1496 1497 // link in foo1 network must fail 1498 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "FirstInFoo1") 1499 c.Assert(err, check.NotNil) 1500 1501 // link in foo2 network must succeed 1502 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "FirstInFoo2") 1503 c.Assert(err, check.IsNil) 1504 } 1505 1506 func (s *DockerNetworkSuite) TestDockerNetworkDisconnectDefault(c *check.C) { 1507 netWorkName1 := "test1" 1508 netWorkName2 := "test2" 1509 containerName := "foo" 1510 1511 dockerCmd(c, "network", "create", netWorkName1) 1512 dockerCmd(c, "network", "create", netWorkName2) 1513 dockerCmd(c, "create", "--name", containerName, "busybox", "top") 1514 dockerCmd(c, "network", "connect", netWorkName1, containerName) 1515 dockerCmd(c, "network", "connect", netWorkName2, containerName) 1516 dockerCmd(c, "network", "disconnect", "bridge", containerName) 1517 1518 dockerCmd(c, "start", containerName) 1519 c.Assert(waitRun(containerName), checker.IsNil) 1520 networks := inspectField(c, containerName, "NetworkSettings.Networks") 1521 c.Assert(networks, checker.Contains, netWorkName1, check.Commentf(fmt.Sprintf("Should contain '%s' network", netWorkName1))) 1522 c.Assert(networks, checker.Contains, netWorkName2, check.Commentf(fmt.Sprintf("Should contain '%s' network", netWorkName2))) 1523 c.Assert(networks, checker.Not(checker.Contains), "bridge", check.Commentf("Should not contain 'bridge' network")) 1524 } 1525 1526 func (s *DockerNetworkSuite) TestDockerNetworkConnectWithAliasOnDefaultNetworks(c *check.C) { 1527 testRequires(c, DaemonIsLinux, NotUserNamespace, NotArm) 1528 1529 defaults := []string{"bridge", "host", "none"} 1530 out, _ := dockerCmd(c, "run", "-d", "--net=none", "busybox", "top") 1531 containerID := strings.TrimSpace(out) 1532 for _, net := range defaults { 1533 res, _, err := dockerCmdWithError("network", "connect", "--alias", "alias"+net, net, containerID) 1534 c.Assert(err, checker.NotNil) 1535 c.Assert(res, checker.Contains, runconfig.ErrUnsupportedNetworkAndAlias.Error()) 1536 } 1537 } 1538 1539 func (s *DockerSuite) TestUserDefinedNetworkConnectDisconnectAlias(c *check.C) { 1540 testRequires(c, DaemonIsLinux, NotUserNamespace, NotArm) 1541 dockerCmd(c, "network", "create", "-d", "bridge", "net1") 1542 dockerCmd(c, "network", "create", "-d", "bridge", "net2") 1543 1544 cid, _ := dockerCmd(c, "run", "-d", "--net=net1", "--name=first", "--net-alias=foo", "busybox", "top") 1545 c.Assert(waitRun("first"), check.IsNil) 1546 1547 dockerCmd(c, "run", "-d", "--net=net1", "--name=second", "busybox", "top") 1548 c.Assert(waitRun("second"), check.IsNil) 1549 1550 // ping first container and its alias 1551 _, _, err := dockerCmdWithError("exec", "second", "ping", "-c", "1", "first") 1552 c.Assert(err, check.IsNil) 1553 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "foo") 1554 c.Assert(err, check.IsNil) 1555 1556 // ping first container's short-id alias 1557 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", stringid.TruncateID(cid)) 1558 c.Assert(err, check.IsNil) 1559 1560 // connect first container to net2 network 1561 dockerCmd(c, "network", "connect", "--alias=bar", "net2", "first") 1562 // connect second container to foo2 network with a different alias for first container 1563 dockerCmd(c, "network", "connect", "net2", "second") 1564 1565 // ping the new alias in network foo2 1566 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "bar") 1567 c.Assert(err, check.IsNil) 1568 1569 // disconnect first container from net1 network 1570 dockerCmd(c, "network", "disconnect", "net1", "first") 1571 1572 // ping to net1 scoped alias "foo" must fail 1573 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "foo") 1574 c.Assert(err, check.NotNil) 1575 1576 // ping to net2 scoped alias "bar" must still succeed 1577 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "bar") 1578 c.Assert(err, check.IsNil) 1579 // ping to net2 scoped alias short-id must still succeed 1580 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", stringid.TruncateID(cid)) 1581 c.Assert(err, check.IsNil) 1582 1583 // verify the alias option is rejected when running on predefined network 1584 out, _, err := dockerCmdWithError("run", "--rm", "--name=any", "--net-alias=any", "busybox", "top") 1585 c.Assert(err, checker.NotNil, check.Commentf("out: %s", out)) 1586 c.Assert(out, checker.Contains, runconfig.ErrUnsupportedNetworkAndAlias.Error()) 1587 1588 // verify the alias option is rejected when connecting to predefined network 1589 out, _, err = dockerCmdWithError("network", "connect", "--alias=any", "bridge", "first") 1590 c.Assert(err, checker.NotNil, check.Commentf("out: %s", out)) 1591 c.Assert(out, checker.Contains, runconfig.ErrUnsupportedNetworkAndAlias.Error()) 1592 } 1593 1594 func (s *DockerSuite) TestUserDefinedNetworkConnectivity(c *check.C) { 1595 testRequires(c, DaemonIsLinux, NotUserNamespace) 1596 dockerCmd(c, "network", "create", "-d", "bridge", "br.net1") 1597 1598 dockerCmd(c, "run", "-d", "--net=br.net1", "--name=c1.net1", "busybox", "top") 1599 c.Assert(waitRun("c1.net1"), check.IsNil) 1600 1601 dockerCmd(c, "run", "-d", "--net=br.net1", "--name=c2.net1", "busybox", "top") 1602 c.Assert(waitRun("c2.net1"), check.IsNil) 1603 1604 // ping first container by its unqualified name 1605 _, _, err := dockerCmdWithError("exec", "c2.net1", "ping", "-c", "1", "c1.net1") 1606 c.Assert(err, check.IsNil) 1607 1608 // ping first container by its qualified name 1609 _, _, err = dockerCmdWithError("exec", "c2.net1", "ping", "-c", "1", "c1.net1.br.net1") 1610 c.Assert(err, check.IsNil) 1611 1612 // ping with first qualified name masked by an additional domain. should fail 1613 _, _, err = dockerCmdWithError("exec", "c2.net1", "ping", "-c", "1", "c1.net1.br.net1.google.com") 1614 c.Assert(err, check.NotNil) 1615 } 1616 1617 func (s *DockerSuite) TestEmbeddedDNSInvalidInput(c *check.C) { 1618 testRequires(c, DaemonIsLinux, NotUserNamespace) 1619 dockerCmd(c, "network", "create", "-d", "bridge", "nw1") 1620 1621 // Sending garbage to embedded DNS shouldn't crash the daemon 1622 dockerCmd(c, "run", "-i", "--net=nw1", "--name=c1", "debian:jessie", "bash", "-c", "echo InvalidQuery > /dev/udp/127.0.0.11/53") 1623 } 1624 1625 func (s *DockerSuite) TestDockerNetworkConnectFailsNoInspectChange(c *check.C) { 1626 dockerCmd(c, "run", "-d", "--name=bb", "busybox", "top") 1627 c.Assert(waitRun("bb"), check.IsNil) 1628 defer dockerCmd(c, "stop", "bb") 1629 1630 ns0 := inspectField(c, "bb", "NetworkSettings.Networks.bridge") 1631 1632 // A failing redundant network connect should not alter current container's endpoint settings 1633 _, _, err := dockerCmdWithError("network", "connect", "bridge", "bb") 1634 c.Assert(err, check.NotNil) 1635 1636 ns1 := inspectField(c, "bb", "NetworkSettings.Networks.bridge") 1637 c.Assert(ns1, check.Equals, ns0) 1638 } 1639 1640 func (s *DockerSuite) TestDockerNetworkInternalMode(c *check.C) { 1641 dockerCmd(c, "network", "create", "--driver=bridge", "--internal", "internal") 1642 assertNwIsAvailable(c, "internal") 1643 nr := getNetworkResource(c, "internal") 1644 c.Assert(nr.Internal, checker.True) 1645 1646 dockerCmd(c, "run", "-d", "--net=internal", "--name=first", "busybox", "top") 1647 c.Assert(waitRun("first"), check.IsNil) 1648 dockerCmd(c, "run", "-d", "--net=internal", "--name=second", "busybox", "top") 1649 c.Assert(waitRun("second"), check.IsNil) 1650 out, _, err := dockerCmdWithError("exec", "first", "ping", "-W", "4", "-c", "1", "www.google.com") 1651 c.Assert(err, check.NotNil) 1652 c.Assert(out, checker.Contains, "ping: bad address") 1653 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "first") 1654 c.Assert(err, check.IsNil) 1655 } 1656 1657 // Test for #21401 1658 func (s *DockerNetworkSuite) TestDockerNetworkCreateDeleteSpecialCharacters(c *check.C) { 1659 dockerCmd(c, "network", "create", "test@#$") 1660 assertNwIsAvailable(c, "test@#$") 1661 dockerCmd(c, "network", "rm", "test@#$") 1662 assertNwNotAvailable(c, "test@#$") 1663 1664 dockerCmd(c, "network", "create", "kiwl$%^") 1665 assertNwIsAvailable(c, "kiwl$%^") 1666 dockerCmd(c, "network", "rm", "kiwl$%^") 1667 assertNwNotAvailable(c, "kiwl$%^") 1668 } 1669 1670 func (s *DockerDaemonSuite) TestDaemonRestartRestoreBridgeNetwork(t *check.C) { 1671 testRequires(t, DaemonIsLinux) 1672 s.d.StartWithBusybox(t, "--live-restore") 1673 defer s.d.Stop(t) 1674 oldCon := "old" 1675 1676 _, err := s.d.Cmd("run", "-d", "--name", oldCon, "-p", "80:80", "busybox", "top") 1677 if err != nil { 1678 t.Fatal(err) 1679 } 1680 oldContainerIP, err := s.d.Cmd("inspect", "-f", "{{ .NetworkSettings.Networks.bridge.IPAddress }}", oldCon) 1681 if err != nil { 1682 t.Fatal(err) 1683 } 1684 // Kill the daemon 1685 if err := s.d.Kill(); err != nil { 1686 t.Fatal(err) 1687 } 1688 1689 // restart the daemon 1690 s.d.Start(t, "--live-restore") 1691 1692 // start a new container, the new container's ip should not be the same with 1693 // old running container. 1694 newCon := "new" 1695 _, err = s.d.Cmd("run", "-d", "--name", newCon, "busybox", "top") 1696 if err != nil { 1697 t.Fatal(err) 1698 } 1699 newContainerIP, err := s.d.Cmd("inspect", "-f", "{{ .NetworkSettings.Networks.bridge.IPAddress }}", newCon) 1700 if err != nil { 1701 t.Fatal(err) 1702 } 1703 if strings.Compare(strings.TrimSpace(oldContainerIP), strings.TrimSpace(newContainerIP)) == 0 { 1704 t.Fatalf("new container ip should not equal to old running container ip") 1705 } 1706 1707 // start a new container, the new container should ping old running container 1708 _, err = s.d.Cmd("run", "-t", "busybox", "ping", "-c", "1", oldContainerIP) 1709 if err != nil { 1710 t.Fatal(err) 1711 } 1712 1713 // start a new container, trying to publish port 80:80 should fail 1714 out, err := s.d.Cmd("run", "-p", "80:80", "-d", "busybox", "top") 1715 if err == nil || !strings.Contains(out, "Bind for 0.0.0.0:80 failed: port is already allocated") { 1716 t.Fatalf("80 port is allocated to old running container, it should failed on allocating to new container") 1717 } 1718 1719 // kill old running container and try to allocate again 1720 _, err = s.d.Cmd("kill", oldCon) 1721 if err != nil { 1722 t.Fatal(err) 1723 } 1724 id, err := s.d.Cmd("run", "-p", "80:80", "-d", "busybox", "top") 1725 if err != nil { 1726 t.Fatal(err) 1727 } 1728 1729 // Cleanup because these containers will not be shut down by daemon 1730 out, err = s.d.Cmd("stop", newCon) 1731 if err != nil { 1732 t.Fatalf("err: %v %v", err, string(out)) 1733 } 1734 _, err = s.d.Cmd("stop", strings.TrimSpace(id)) 1735 if err != nil { 1736 t.Fatal(err) 1737 } 1738 } 1739 1740 func (s *DockerNetworkSuite) TestDockerNetworkFlagAlias(c *check.C) { 1741 dockerCmd(c, "network", "create", "user") 1742 output, status := dockerCmd(c, "run", "--rm", "--network=user", "--network-alias=foo", "busybox", "true") 1743 c.Assert(status, checker.Equals, 0, check.Commentf("unexpected status code %d (%s)", status, output)) 1744 1745 output, status, _ = dockerCmdWithError("run", "--rm", "--net=user", "--network=user", "busybox", "true") 1746 c.Assert(status, checker.Equals, 0, check.Commentf("unexpected status code %d (%s)", status, output)) 1747 1748 output, status, _ = dockerCmdWithError("run", "--rm", "--network=user", "--net-alias=foo", "--network-alias=bar", "busybox", "true") 1749 c.Assert(status, checker.Equals, 0, check.Commentf("unexpected status code %d (%s)", status, output)) 1750 } 1751 1752 func (s *DockerNetworkSuite) TestDockerNetworkValidateIP(c *check.C) { 1753 _, _, err := dockerCmdWithError("network", "create", "--ipv6", "--subnet=172.28.0.0/16", "--subnet=2001:db8:1234::/64", "mynet") 1754 c.Assert(err, check.IsNil) 1755 assertNwIsAvailable(c, "mynet") 1756 1757 _, _, err = dockerCmdWithError("run", "-d", "--name", "mynet0", "--net=mynet", "--ip", "172.28.99.88", "--ip6", "2001:db8:1234::9988", "busybox", "top") 1758 c.Assert(err, check.IsNil) 1759 c.Assert(waitRun("mynet0"), check.IsNil) 1760 verifyIPAddressConfig(c, "mynet0", "mynet", "172.28.99.88", "2001:db8:1234::9988") 1761 verifyIPAddresses(c, "mynet0", "mynet", "172.28.99.88", "2001:db8:1234::9988") 1762 1763 _, _, err = dockerCmdWithError("run", "--net=mynet", "--ip", "mynet_ip", "--ip6", "2001:db8:1234::9999", "busybox", "top") 1764 c.Assert(err.Error(), checker.Contains, "invalid IPv4 address") 1765 _, _, err = dockerCmdWithError("run", "--net=mynet", "--ip", "172.28.99.99", "--ip6", "mynet_ip6", "busybox", "top") 1766 c.Assert(err.Error(), checker.Contains, "invalid IPv6 address") 1767 // This is a case of IPv4 address to `--ip6` 1768 _, _, err = dockerCmdWithError("run", "--net=mynet", "--ip6", "172.28.99.99", "busybox", "top") 1769 c.Assert(err.Error(), checker.Contains, "invalid IPv6 address") 1770 // This is a special case of an IPv4-mapped IPv6 address 1771 _, _, err = dockerCmdWithError("run", "--net=mynet", "--ip6", "::ffff:172.28.99.99", "busybox", "top") 1772 c.Assert(err.Error(), checker.Contains, "invalid IPv6 address") 1773 } 1774 1775 // Test case for 26220 1776 func (s *DockerNetworkSuite) TestDockerNetworkDisconnectFromBridge(c *check.C) { 1777 out, _ := dockerCmd(c, "network", "inspect", "--format", "{{.Id}}", "bridge") 1778 1779 network := strings.TrimSpace(out) 1780 1781 name := "test" 1782 dockerCmd(c, "create", "--name", name, "busybox", "top") 1783 1784 _, _, err := dockerCmdWithError("network", "disconnect", network, name) 1785 c.Assert(err, check.IsNil) 1786 } 1787 1788 // TestConntrackFlowsLeak covers the failure scenario of ticket: https://github.com/docker/docker/issues/8795 1789 // Validates that conntrack is correctly cleaned once a container is destroyed 1790 func (s *DockerNetworkSuite) TestConntrackFlowsLeak(c *check.C) { 1791 testRequires(c, IsAmd64, DaemonIsLinux, Network, SameHostDaemon) 1792 1793 // Create a new network 1794 cli.DockerCmd(c, "network", "create", "--subnet=192.168.10.0/24", "--gateway=192.168.10.1", "-o", "com.docker.network.bridge.host_binding_ipv4=192.168.10.1", "testbind") 1795 assertNwIsAvailable(c, "testbind") 1796 1797 // Launch the server, this will remain listening on an exposed port and reply to any request in a ping/pong fashion 1798 cmd := "while true; do echo hello | nc -w 1 -lu 8080; done" 1799 cli.DockerCmd(c, "run", "-d", "--name", "server", "--net", "testbind", "-p", "8080:8080/udp", "appropriate/nc", "sh", "-c", cmd) 1800 1801 // Launch a container client, here the objective is to create a flow that is natted in order to expose the bug 1802 cmd = "echo world | nc -q 1 -u 192.168.10.1 8080" 1803 cli.DockerCmd(c, "run", "-d", "--name", "client", "--net=host", "appropriate/nc", "sh", "-c", cmd) 1804 1805 // Get all the flows using netlink 1806 flows, err := netlink.ConntrackTableList(netlink.ConntrackTable, unix.AF_INET) 1807 c.Assert(err, check.IsNil) 1808 var flowMatch int 1809 for _, flow := range flows { 1810 // count only the flows that we are interested in, skipping others that can be laying around the host 1811 if flow.Forward.Protocol == unix.IPPROTO_UDP && 1812 flow.Forward.DstIP.Equal(net.ParseIP("192.168.10.1")) && 1813 flow.Forward.DstPort == 8080 { 1814 flowMatch++ 1815 } 1816 } 1817 // The client should have created only 1 flow 1818 c.Assert(flowMatch, checker.Equals, 1) 1819 1820 // Now delete the server, this will trigger the conntrack cleanup 1821 cli.DockerCmd(c, "rm", "-fv", "server") 1822 1823 // Fetch again all the flows and validate that there is no server flow in the conntrack laying around 1824 flows, err = netlink.ConntrackTableList(netlink.ConntrackTable, unix.AF_INET) 1825 c.Assert(err, check.IsNil) 1826 flowMatch = 0 1827 for _, flow := range flows { 1828 if flow.Forward.Protocol == unix.IPPROTO_UDP && 1829 flow.Forward.DstIP.Equal(net.ParseIP("192.168.10.1")) && 1830 flow.Forward.DstPort == 8080 { 1831 flowMatch++ 1832 } 1833 } 1834 // All the flows have to be gone 1835 c.Assert(flowMatch, checker.Equals, 0) 1836 }