github.com/endocode/docker@v1.4.2-0.20160113120958-46eb4700391e/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 "sort" 14 "strings" 15 16 "github.com/docker/docker/pkg/integration/checker" 17 "github.com/docker/docker/runconfig" 18 "github.com/docker/engine-api/types" 19 "github.com/docker/engine-api/types/versions/v1p20" 20 "github.com/docker/libnetwork/driverapi" 21 remoteapi "github.com/docker/libnetwork/drivers/remote/api" 22 "github.com/docker/libnetwork/ipamapi" 23 remoteipam "github.com/docker/libnetwork/ipams/remote/api" 24 "github.com/docker/libnetwork/netlabel" 25 "github.com/go-check/check" 26 "github.com/vishvananda/netlink" 27 ) 28 29 const dummyNetworkDriver = "dummy-network-driver" 30 const dummyIpamDriver = "dummy-ipam-driver" 31 32 var remoteDriverNetworkRequest remoteapi.CreateNetworkRequest 33 34 func init() { 35 check.Suite(&DockerNetworkSuite{ 36 ds: &DockerSuite{}, 37 }) 38 } 39 40 type DockerNetworkSuite struct { 41 server *httptest.Server 42 ds *DockerSuite 43 d *Daemon 44 } 45 46 func (s *DockerNetworkSuite) SetUpTest(c *check.C) { 47 s.d = NewDaemon(c) 48 } 49 50 func (s *DockerNetworkSuite) TearDownTest(c *check.C) { 51 s.d.Stop() 52 s.ds.TearDownTest(c) 53 } 54 55 func (s *DockerNetworkSuite) SetUpSuite(c *check.C) { 56 mux := http.NewServeMux() 57 s.server = httptest.NewServer(mux) 58 c.Assert(s.server, check.NotNil, check.Commentf("Failed to start a HTTP Server")) 59 60 mux.HandleFunc("/Plugin.Activate", func(w http.ResponseWriter, r *http.Request) { 61 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 62 fmt.Fprintf(w, `{"Implements": ["%s", "%s"]}`, driverapi.NetworkPluginEndpointType, ipamapi.PluginEndpointType) 63 }) 64 65 // Network driver implementation 66 mux.HandleFunc(fmt.Sprintf("/%s.GetCapabilities", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 67 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 68 fmt.Fprintf(w, `{"Scope":"local"}`) 69 }) 70 71 mux.HandleFunc(fmt.Sprintf("/%s.CreateNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 72 err := json.NewDecoder(r.Body).Decode(&remoteDriverNetworkRequest) 73 if err != nil { 74 http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest) 75 return 76 } 77 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 78 fmt.Fprintf(w, "null") 79 }) 80 81 mux.HandleFunc(fmt.Sprintf("/%s.DeleteNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 82 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 83 fmt.Fprintf(w, "null") 84 }) 85 86 mux.HandleFunc(fmt.Sprintf("/%s.CreateEndpoint", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 87 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 88 fmt.Fprintf(w, `{"Interface":{"MacAddress":"a0:b1:c2:d3:e4:f5"}}`) 89 }) 90 91 mux.HandleFunc(fmt.Sprintf("/%s.Join", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 92 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 93 94 veth := &netlink.Veth{ 95 LinkAttrs: netlink.LinkAttrs{Name: "randomIfName", TxQLen: 0}, PeerName: "cnt0"} 96 if err := netlink.LinkAdd(veth); err != nil { 97 fmt.Fprintf(w, `{"Error":"failed to add veth pair: `+err.Error()+`"}`) 98 } else { 99 fmt.Fprintf(w, `{"InterfaceName":{ "SrcName":"cnt0", "DstPrefix":"veth"}}`) 100 } 101 }) 102 103 mux.HandleFunc(fmt.Sprintf("/%s.Leave", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 104 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 105 fmt.Fprintf(w, "null") 106 }) 107 108 mux.HandleFunc(fmt.Sprintf("/%s.DeleteEndpoint", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 109 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 110 if link, err := netlink.LinkByName("cnt0"); err == nil { 111 netlink.LinkDel(link) 112 } 113 fmt.Fprintf(w, "null") 114 }) 115 116 // Ipam Driver implementation 117 var ( 118 poolRequest remoteipam.RequestPoolRequest 119 poolReleaseReq remoteipam.ReleasePoolRequest 120 addressRequest remoteipam.RequestAddressRequest 121 addressReleaseReq remoteipam.ReleaseAddressRequest 122 lAS = "localAS" 123 gAS = "globalAS" 124 pool = "172.28.0.0/16" 125 poolID = lAS + "/" + pool 126 gw = "172.28.255.254/16" 127 ) 128 129 mux.HandleFunc(fmt.Sprintf("/%s.GetDefaultAddressSpaces", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 130 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 131 fmt.Fprintf(w, `{"LocalDefaultAddressSpace":"`+lAS+`", "GlobalDefaultAddressSpace": "`+gAS+`"}`) 132 }) 133 134 mux.HandleFunc(fmt.Sprintf("/%s.RequestPool", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 135 err := json.NewDecoder(r.Body).Decode(&poolRequest) 136 if err != nil { 137 http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest) 138 return 139 } 140 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 141 if poolRequest.AddressSpace != lAS && poolRequest.AddressSpace != gAS { 142 fmt.Fprintf(w, `{"Error":"Unknown address space in pool request: `+poolRequest.AddressSpace+`"}`) 143 } else if poolRequest.Pool != "" && poolRequest.Pool != pool { 144 fmt.Fprintf(w, `{"Error":"Cannot handle explicit pool requests yet"}`) 145 } else { 146 fmt.Fprintf(w, `{"PoolID":"`+poolID+`", "Pool":"`+pool+`"}`) 147 } 148 }) 149 150 mux.HandleFunc(fmt.Sprintf("/%s.RequestAddress", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 151 err := json.NewDecoder(r.Body).Decode(&addressRequest) 152 if err != nil { 153 http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest) 154 return 155 } 156 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 157 // make sure libnetwork is now querying on the expected pool id 158 if addressRequest.PoolID != poolID { 159 fmt.Fprintf(w, `{"Error":"unknown pool id"}`) 160 } else if addressRequest.Address != "" { 161 fmt.Fprintf(w, `{"Error":"Cannot handle explicit address requests yet"}`) 162 } else { 163 fmt.Fprintf(w, `{"Address":"`+gw+`"}`) 164 } 165 }) 166 167 mux.HandleFunc(fmt.Sprintf("/%s.ReleaseAddress", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 168 err := json.NewDecoder(r.Body).Decode(&addressReleaseReq) 169 if err != nil { 170 http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest) 171 return 172 } 173 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 174 // make sure libnetwork is now asking to release the expected address from the expected poolid 175 if addressRequest.PoolID != poolID { 176 fmt.Fprintf(w, `{"Error":"unknown pool id"}`) 177 } else if addressReleaseReq.Address != gw { 178 fmt.Fprintf(w, `{"Error":"unknown address"}`) 179 } else { 180 fmt.Fprintf(w, "null") 181 } 182 }) 183 184 mux.HandleFunc(fmt.Sprintf("/%s.ReleasePool", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 185 err := json.NewDecoder(r.Body).Decode(&poolReleaseReq) 186 if err != nil { 187 http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest) 188 return 189 } 190 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 191 // make sure libnetwork is now asking to release the expected poolid 192 if addressRequest.PoolID != poolID { 193 fmt.Fprintf(w, `{"Error":"unknown pool id"}`) 194 } else { 195 fmt.Fprintf(w, "null") 196 } 197 }) 198 199 err := os.MkdirAll("/etc/docker/plugins", 0755) 200 c.Assert(err, checker.IsNil) 201 202 fileName := fmt.Sprintf("/etc/docker/plugins/%s.spec", dummyNetworkDriver) 203 err = ioutil.WriteFile(fileName, []byte(s.server.URL), 0644) 204 c.Assert(err, checker.IsNil) 205 206 ipamFileName := fmt.Sprintf("/etc/docker/plugins/%s.spec", dummyIpamDriver) 207 err = ioutil.WriteFile(ipamFileName, []byte(s.server.URL), 0644) 208 c.Assert(err, checker.IsNil) 209 } 210 211 func (s *DockerNetworkSuite) TearDownSuite(c *check.C) { 212 if s.server == nil { 213 return 214 } 215 216 s.server.Close() 217 218 err := os.RemoveAll("/etc/docker/plugins") 219 c.Assert(err, checker.IsNil) 220 } 221 222 func assertNwIsAvailable(c *check.C, name string) { 223 if !isNwPresent(c, name) { 224 c.Fatalf("Network %s not found in network ls o/p", name) 225 } 226 } 227 228 func assertNwNotAvailable(c *check.C, name string) { 229 if isNwPresent(c, name) { 230 c.Fatalf("Found network %s in network ls o/p", name) 231 } 232 } 233 234 func isNwPresent(c *check.C, name string) bool { 235 out, _ := dockerCmd(c, "network", "ls") 236 lines := strings.Split(out, "\n") 237 for i := 1; i < len(lines)-1; i++ { 238 netFields := strings.Fields(lines[i]) 239 if netFields[1] == name { 240 return true 241 } 242 } 243 return false 244 } 245 246 // assertNwList checks network list retrived with ls command 247 // equals to expected network list 248 // note: out should be `network ls [option]` result 249 func assertNwList(c *check.C, out string, expectNws []string) { 250 lines := strings.Split(out, "\n") 251 var nwList []string 252 for _, line := range lines[1 : len(lines)-1] { 253 netFields := strings.Fields(line) 254 // wrap all network name in nwList 255 nwList = append(nwList, netFields[1]) 256 } 257 // first need to sort out and expected 258 sort.StringSlice(nwList).Sort() 259 sort.StringSlice(expectNws).Sort() 260 261 // network ls should contains all expected networks 262 c.Assert(nwList, checker.DeepEquals, expectNws) 263 } 264 265 func getNwResource(c *check.C, name string) *types.NetworkResource { 266 out, _ := dockerCmd(c, "network", "inspect", name) 267 nr := []types.NetworkResource{} 268 err := json.Unmarshal([]byte(out), &nr) 269 c.Assert(err, check.IsNil) 270 return &nr[0] 271 } 272 273 func (s *DockerNetworkSuite) TestDockerNetworkLsDefault(c *check.C) { 274 defaults := []string{"bridge", "host", "none"} 275 for _, nn := range defaults { 276 assertNwIsAvailable(c, nn) 277 } 278 } 279 280 func (s *DockerNetworkSuite) TestDockerNetworkLsFilter(c *check.C) { 281 out, _ := dockerCmd(c, "network", "create", "dev") 282 defer func() { 283 dockerCmd(c, "network", "rm", "dev") 284 }() 285 containerID := strings.TrimSpace(out) 286 287 // filter with partial ID and partial name 288 // only show 'bridge' and 'dev' network 289 out, _ = dockerCmd(c, "network", "ls", "-f", "id="+containerID[0:5], "-f", "name=dge") 290 assertNwList(c, out, []string{"dev", "bridge"}) 291 292 // only show built-in network (bridge, none, host) 293 out, _ = dockerCmd(c, "network", "ls", "-f", "type=builtin") 294 assertNwList(c, out, []string{"bridge", "none", "host"}) 295 296 // only show custom networks (dev) 297 out, _ = dockerCmd(c, "network", "ls", "-f", "type=custom") 298 assertNwList(c, out, []string{"dev"}) 299 300 // show all networks with filter 301 // it should be equivalent of ls without option 302 out, _ = dockerCmd(c, "network", "ls", "-f", "type=custom", "-f", "type=builtin") 303 assertNwList(c, out, []string{"dev", "bridge", "host", "none"}) 304 } 305 306 func (s *DockerNetworkSuite) TestDockerNetworkCreateDelete(c *check.C) { 307 dockerCmd(c, "network", "create", "test") 308 assertNwIsAvailable(c, "test") 309 310 dockerCmd(c, "network", "rm", "test") 311 assertNwNotAvailable(c, "test") 312 } 313 314 func (s *DockerSuite) TestDockerNetworkDeleteNotExists(c *check.C) { 315 out, _, err := dockerCmdWithError("network", "rm", "test") 316 c.Assert(err, checker.NotNil, check.Commentf("%v", out)) 317 } 318 319 func (s *DockerSuite) TestDockerNetworkDeleteMultiple(c *check.C) { 320 dockerCmd(c, "network", "create", "testDelMulti0") 321 assertNwIsAvailable(c, "testDelMulti0") 322 dockerCmd(c, "network", "create", "testDelMulti1") 323 assertNwIsAvailable(c, "testDelMulti1") 324 dockerCmd(c, "network", "create", "testDelMulti2") 325 assertNwIsAvailable(c, "testDelMulti2") 326 out, _ := dockerCmd(c, "run", "-d", "--net", "testDelMulti2", "busybox", "top") 327 waitRun(strings.TrimSpace(out)) 328 329 // delete three networks at the same time, since testDelMulti2 330 // contains active container, it's deletion should fail. 331 out, _, err := dockerCmdWithError("network", "rm", "testDelMulti0", "testDelMulti1", "testDelMulti2") 332 // err should not be nil due to deleting testDelMulti2 failed. 333 c.Assert(err, checker.NotNil, check.Commentf("out: %s", out)) 334 // testDelMulti2 should fail due to network has active endpoints 335 c.Assert(out, checker.Contains, "has active endpoints") 336 assertNwNotAvailable(c, "testDelMulti0") 337 assertNwNotAvailable(c, "testDelMulti1") 338 // testDelMulti2 can't be deleted, so it should exists 339 assertNwIsAvailable(c, "testDelMulti2") 340 } 341 342 func (s *DockerSuite) TestDockerNetworkInspect(c *check.C) { 343 out, _ := dockerCmd(c, "network", "inspect", "host") 344 networkResources := []types.NetworkResource{} 345 err := json.Unmarshal([]byte(out), &networkResources) 346 c.Assert(err, check.IsNil) 347 c.Assert(networkResources, checker.HasLen, 1) 348 349 out, _ = dockerCmd(c, "network", "inspect", "--format='{{ .Name }}'", "host") 350 c.Assert(strings.TrimSpace(out), check.Equals, "host") 351 } 352 353 func (s *DockerSuite) TestDockerInspectMultipleNetwork(c *check.C) { 354 out, _ := dockerCmd(c, "network", "inspect", "host", "none") 355 networkResources := []types.NetworkResource{} 356 err := json.Unmarshal([]byte(out), &networkResources) 357 c.Assert(err, check.IsNil) 358 c.Assert(networkResources, checker.HasLen, 2) 359 360 // Should print an error, return an exitCode 1 *but* should print the host network 361 out, exitCode, err := dockerCmdWithError("network", "inspect", "host", "nonexistent") 362 c.Assert(err, checker.NotNil) 363 c.Assert(exitCode, checker.Equals, 1) 364 c.Assert(out, checker.Contains, "Error: No such network: nonexistent") 365 networkResources = []types.NetworkResource{} 366 inspectOut := strings.SplitN(out, "\nError: No such network: nonexistent\n", 2)[0] 367 err = json.Unmarshal([]byte(inspectOut), &networkResources) 368 c.Assert(networkResources, checker.HasLen, 1) 369 370 // Should print an error and return an exitCode, nothing else 371 out, exitCode, err = dockerCmdWithError("network", "inspect", "nonexistent") 372 c.Assert(err, checker.NotNil) 373 c.Assert(exitCode, checker.Equals, 1) 374 c.Assert(out, checker.Contains, "Error: No such network: nonexistent") 375 } 376 377 func (s *DockerSuite) TestDockerInspectNetworkWithContainerName(c *check.C) { 378 dockerCmd(c, "network", "create", "brNetForInspect") 379 assertNwIsAvailable(c, "brNetForInspect") 380 defer func() { 381 dockerCmd(c, "network", "rm", "brNetForInspect") 382 assertNwNotAvailable(c, "brNetForInspect") 383 }() 384 385 out, _ := dockerCmd(c, "run", "-d", "--name", "testNetInspect1", "--net", "brNetForInspect", "busybox", "top") 386 c.Assert(waitRun("testNetInspect1"), check.IsNil) 387 containerID := strings.TrimSpace(out) 388 defer func() { 389 // we don't stop container by name, because we'll rename it later 390 dockerCmd(c, "stop", containerID) 391 }() 392 393 out, _ = dockerCmd(c, "network", "inspect", "brNetForInspect") 394 networkResources := []types.NetworkResource{} 395 err := json.Unmarshal([]byte(out), &networkResources) 396 c.Assert(err, check.IsNil) 397 c.Assert(networkResources, checker.HasLen, 1) 398 container, ok := networkResources[0].Containers[containerID] 399 c.Assert(ok, checker.True) 400 c.Assert(container.Name, checker.Equals, "testNetInspect1") 401 402 // rename container and check docker inspect output update 403 newName := "HappyNewName" 404 dockerCmd(c, "rename", "testNetInspect1", newName) 405 406 // check whether network inspect works properly 407 out, _ = dockerCmd(c, "network", "inspect", "brNetForInspect") 408 newNetRes := []types.NetworkResource{} 409 err = json.Unmarshal([]byte(out), &newNetRes) 410 c.Assert(err, check.IsNil) 411 c.Assert(newNetRes, checker.HasLen, 1) 412 container1, ok := newNetRes[0].Containers[containerID] 413 c.Assert(ok, checker.True) 414 c.Assert(container1.Name, checker.Equals, newName) 415 416 } 417 418 func (s *DockerNetworkSuite) TestDockerNetworkConnectDisconnect(c *check.C) { 419 dockerCmd(c, "network", "create", "test") 420 assertNwIsAvailable(c, "test") 421 nr := getNwResource(c, "test") 422 423 c.Assert(nr.Name, checker.Equals, "test") 424 c.Assert(len(nr.Containers), checker.Equals, 0) 425 426 // run a container 427 out, _ := dockerCmd(c, "run", "-d", "--name", "test", "busybox", "top") 428 c.Assert(waitRun("test"), check.IsNil) 429 containerID := strings.TrimSpace(out) 430 431 // connect the container to the test network 432 dockerCmd(c, "network", "connect", "test", containerID) 433 434 // inspect the network to make sure container is connected 435 nr = getNetworkResource(c, nr.ID) 436 c.Assert(len(nr.Containers), checker.Equals, 1) 437 c.Assert(nr.Containers[containerID], check.NotNil) 438 439 // check if container IP matches network inspect 440 ip, _, err := net.ParseCIDR(nr.Containers[containerID].IPv4Address) 441 c.Assert(err, check.IsNil) 442 containerIP := findContainerIP(c, "test", "test") 443 c.Assert(ip.String(), checker.Equals, containerIP) 444 445 // disconnect container from the network 446 dockerCmd(c, "network", "disconnect", "test", containerID) 447 nr = getNwResource(c, "test") 448 c.Assert(nr.Name, checker.Equals, "test") 449 c.Assert(len(nr.Containers), checker.Equals, 0) 450 451 dockerCmd(c, "network", "rm", "test") 452 assertNwNotAvailable(c, "test") 453 } 454 455 func (s *DockerNetworkSuite) TestDockerNetworkIpamMultipleNetworks(c *check.C) { 456 // test0 bridge network 457 dockerCmd(c, "network", "create", "--subnet=192.168.0.0/16", "test1") 458 assertNwIsAvailable(c, "test1") 459 460 // test2 bridge network does not overlap 461 dockerCmd(c, "network", "create", "--subnet=192.169.0.0/16", "test2") 462 assertNwIsAvailable(c, "test2") 463 464 // for networks w/o ipam specified, docker will choose proper non-overlapping subnets 465 dockerCmd(c, "network", "create", "test3") 466 assertNwIsAvailable(c, "test3") 467 dockerCmd(c, "network", "create", "test4") 468 assertNwIsAvailable(c, "test4") 469 dockerCmd(c, "network", "create", "test5") 470 assertNwIsAvailable(c, "test5") 471 472 // test network with multiple subnets 473 // bridge network doesn't support multiple subnets. hence, use a dummy driver that supports 474 475 dockerCmd(c, "network", "create", "-d", dummyNetworkDriver, "--subnet=192.168.0.0/16", "--subnet=192.170.0.0/16", "test6") 476 assertNwIsAvailable(c, "test6") 477 478 // test network with multiple subnets with valid ipam combinations 479 // also check same subnet across networks when the driver supports it. 480 dockerCmd(c, "network", "create", "-d", dummyNetworkDriver, 481 "--subnet=192.168.0.0/16", "--subnet=192.170.0.0/16", 482 "--gateway=192.168.0.100", "--gateway=192.170.0.100", 483 "--ip-range=192.168.1.0/24", 484 "--aux-address", "a=192.168.1.5", "--aux-address", "b=192.168.1.6", 485 "--aux-address", "a=192.170.1.5", "--aux-address", "b=192.170.1.6", 486 "test7") 487 assertNwIsAvailable(c, "test7") 488 489 // cleanup 490 for i := 1; i < 8; i++ { 491 dockerCmd(c, "network", "rm", fmt.Sprintf("test%d", i)) 492 } 493 } 494 495 func (s *DockerNetworkSuite) TestDockerNetworkCustomIpam(c *check.C) { 496 // Create a bridge network using custom ipam driver 497 dockerCmd(c, "network", "create", "--ipam-driver", dummyIpamDriver, "br0") 498 assertNwIsAvailable(c, "br0") 499 500 // Verify expected network ipam fields are there 501 nr := getNetworkResource(c, "br0") 502 c.Assert(nr.Driver, checker.Equals, "bridge") 503 c.Assert(nr.IPAM.Driver, checker.Equals, dummyIpamDriver) 504 505 // remove network and exercise remote ipam driver 506 dockerCmd(c, "network", "rm", "br0") 507 assertNwNotAvailable(c, "br0") 508 } 509 510 func (s *DockerNetworkSuite) TestDockerNetworkInspect(c *check.C) { 511 // if unspecified, network gateway will be selected from inside preferred pool 512 dockerCmd(c, "network", "create", "--driver=bridge", "--subnet=172.28.0.0/16", "--ip-range=172.28.5.0/24", "--gateway=172.28.5.254", "br0") 513 assertNwIsAvailable(c, "br0") 514 515 nr := getNetworkResource(c, "br0") 516 c.Assert(nr.Driver, checker.Equals, "bridge") 517 c.Assert(nr.Scope, checker.Equals, "local") 518 c.Assert(nr.IPAM.Driver, checker.Equals, "default") 519 c.Assert(len(nr.IPAM.Config), checker.Equals, 1) 520 c.Assert(nr.IPAM.Config[0].Subnet, checker.Equals, "172.28.0.0/16") 521 c.Assert(nr.IPAM.Config[0].IPRange, checker.Equals, "172.28.5.0/24") 522 c.Assert(nr.IPAM.Config[0].Gateway, checker.Equals, "172.28.5.254") 523 dockerCmd(c, "network", "rm", "br0") 524 } 525 526 func (s *DockerNetworkSuite) TestDockerNetworkIpamInvalidCombinations(c *check.C) { 527 // network with ip-range out of subnet range 528 _, _, err := dockerCmdWithError("network", "create", "--subnet=192.168.0.0/16", "--ip-range=192.170.0.0/16", "test") 529 c.Assert(err, check.NotNil) 530 531 // network with multiple gateways for a single subnet 532 _, _, err = dockerCmdWithError("network", "create", "--subnet=192.168.0.0/16", "--gateway=192.168.0.1", "--gateway=192.168.0.2", "test") 533 c.Assert(err, check.NotNil) 534 535 // Multiple overlapping subnets in the same network must fail 536 _, _, err = dockerCmdWithError("network", "create", "--subnet=192.168.0.0/16", "--subnet=192.168.1.0/16", "test") 537 c.Assert(err, check.NotNil) 538 539 // overlapping subnets across networks must fail 540 // create a valid test0 network 541 dockerCmd(c, "network", "create", "--subnet=192.168.0.0/16", "test0") 542 assertNwIsAvailable(c, "test0") 543 // create an overlapping test1 network 544 _, _, err = dockerCmdWithError("network", "create", "--subnet=192.168.128.0/17", "test1") 545 c.Assert(err, check.NotNil) 546 dockerCmd(c, "network", "rm", "test0") 547 } 548 549 func (s *DockerNetworkSuite) TestDockerNetworkDriverOptions(c *check.C) { 550 dockerCmd(c, "network", "create", "-d", dummyNetworkDriver, "-o", "opt1=drv1", "-o", "opt2=drv2", "testopt") 551 assertNwIsAvailable(c, "testopt") 552 gopts := remoteDriverNetworkRequest.Options[netlabel.GenericData] 553 c.Assert(gopts, checker.NotNil) 554 opts, ok := gopts.(map[string]interface{}) 555 c.Assert(ok, checker.Equals, true) 556 c.Assert(opts["opt1"], checker.Equals, "drv1") 557 c.Assert(opts["opt2"], checker.Equals, "drv2") 558 dockerCmd(c, "network", "rm", "testopt") 559 560 } 561 562 func (s *DockerDaemonSuite) TestDockerNetworkNoDiscoveryDefaultBridgeNetwork(c *check.C) { 563 testRequires(c, ExecSupport) 564 // On default bridge network built-in service discovery should not happen 565 hostsFile := "/etc/hosts" 566 bridgeName := "external-bridge" 567 bridgeIP := "192.169.255.254/24" 568 out, err := createInterface(c, "bridge", bridgeName, bridgeIP) 569 c.Assert(err, check.IsNil, check.Commentf(out)) 570 defer deleteInterface(c, bridgeName) 571 572 err = s.d.StartWithBusybox("--bridge", bridgeName) 573 c.Assert(err, check.IsNil) 574 defer s.d.Restart() 575 576 // run two containers and store first container's etc/hosts content 577 out, err = s.d.Cmd("run", "-d", "busybox", "top") 578 c.Assert(err, check.IsNil) 579 cid1 := strings.TrimSpace(out) 580 defer s.d.Cmd("stop", cid1) 581 582 hosts, err := s.d.Cmd("exec", cid1, "cat", hostsFile) 583 c.Assert(err, checker.IsNil) 584 585 out, err = s.d.Cmd("run", "-d", "--name", "container2", "busybox", "top") 586 c.Assert(err, check.IsNil) 587 cid2 := strings.TrimSpace(out) 588 589 // verify first container's etc/hosts file has not changed after spawning the second named container 590 hostsPost, err := s.d.Cmd("exec", cid1, "cat", hostsFile) 591 c.Assert(err, checker.IsNil) 592 c.Assert(string(hosts), checker.Equals, string(hostsPost), 593 check.Commentf("Unexpected %s change on second container creation", hostsFile)) 594 595 // stop container 2 and verify first container's etc/hosts has not changed 596 _, err = s.d.Cmd("stop", cid2) 597 c.Assert(err, check.IsNil) 598 599 hostsPost, err = s.d.Cmd("exec", cid1, "cat", hostsFile) 600 c.Assert(err, checker.IsNil) 601 c.Assert(string(hosts), checker.Equals, string(hostsPost), 602 check.Commentf("Unexpected %s change on second container creation", hostsFile)) 603 604 // but discovery is on when connecting to non default bridge network 605 network := "anotherbridge" 606 out, err = s.d.Cmd("network", "create", network) 607 c.Assert(err, check.IsNil, check.Commentf(out)) 608 defer s.d.Cmd("network", "rm", network) 609 610 out, err = s.d.Cmd("network", "connect", network, cid1) 611 c.Assert(err, check.IsNil, check.Commentf(out)) 612 613 hosts, err = s.d.Cmd("exec", cid1, "cat", hostsFile) 614 c.Assert(err, checker.IsNil) 615 616 hostsPost, err = s.d.Cmd("exec", cid1, "cat", hostsFile) 617 c.Assert(err, checker.IsNil) 618 c.Assert(string(hosts), checker.Equals, string(hostsPost), 619 check.Commentf("Unexpected %s change on second network connection", hostsFile)) 620 } 621 622 func (s *DockerNetworkSuite) TestDockerNetworkAnonymousEndpoint(c *check.C) { 623 testRequires(c, ExecSupport) 624 hostsFile := "/etc/hosts" 625 cstmBridgeNw := "custom-bridge-nw" 626 cstmBridgeNw1 := "custom-bridge-nw1" 627 628 dockerCmd(c, "network", "create", "-d", "bridge", cstmBridgeNw) 629 assertNwIsAvailable(c, cstmBridgeNw) 630 631 // run two anonymous containers and store their etc/hosts content 632 out, _ := dockerCmd(c, "run", "-d", "--net", cstmBridgeNw, "busybox", "top") 633 cid1 := strings.TrimSpace(out) 634 635 hosts1, err := readContainerFileWithExec(cid1, hostsFile) 636 c.Assert(err, checker.IsNil) 637 638 out, _ = dockerCmd(c, "run", "-d", "--net", cstmBridgeNw, "busybox", "top") 639 cid2 := strings.TrimSpace(out) 640 641 hosts2, err := readContainerFileWithExec(cid2, hostsFile) 642 c.Assert(err, checker.IsNil) 643 644 // verify first container etc/hosts file has not changed 645 hosts1post, err := readContainerFileWithExec(cid1, hostsFile) 646 c.Assert(err, checker.IsNil) 647 c.Assert(string(hosts1), checker.Equals, string(hosts1post), 648 check.Commentf("Unexpected %s change on anonymous container creation", hostsFile)) 649 650 // Connect the 2nd container to a new network and verify the 651 // first container /etc/hosts file still hasn't changed. 652 dockerCmd(c, "network", "create", "-d", "bridge", cstmBridgeNw1) 653 assertNwIsAvailable(c, cstmBridgeNw1) 654 655 dockerCmd(c, "network", "connect", cstmBridgeNw1, cid2) 656 657 hosts2, err = readContainerFileWithExec(cid2, hostsFile) 658 c.Assert(err, checker.IsNil) 659 660 hosts1post, err = readContainerFileWithExec(cid1, hostsFile) 661 c.Assert(err, checker.IsNil) 662 c.Assert(string(hosts1), checker.Equals, string(hosts1post), 663 check.Commentf("Unexpected %s change on container connect", hostsFile)) 664 665 // start a named container 666 cName := "AnyName" 667 out, _ = dockerCmd(c, "run", "-d", "--net", cstmBridgeNw, "--name", cName, "busybox", "top") 668 cid3 := strings.TrimSpace(out) 669 670 // verify that container 1 and 2 can ping the named container 671 dockerCmd(c, "exec", cid1, "ping", "-c", "1", cName) 672 dockerCmd(c, "exec", cid2, "ping", "-c", "1", cName) 673 674 // Stop named container and verify first two containers' etc/hosts file hasn't changed 675 dockerCmd(c, "stop", cid3) 676 hosts1post, err = readContainerFileWithExec(cid1, hostsFile) 677 c.Assert(err, checker.IsNil) 678 c.Assert(string(hosts1), checker.Equals, string(hosts1post), 679 check.Commentf("Unexpected %s change on name container creation", hostsFile)) 680 681 hosts2post, err := readContainerFileWithExec(cid2, hostsFile) 682 c.Assert(err, checker.IsNil) 683 c.Assert(string(hosts2), checker.Equals, string(hosts2post), 684 check.Commentf("Unexpected %s change on name container creation", hostsFile)) 685 686 // verify that container 1 and 2 can't ping the named container now 687 _, _, err = dockerCmdWithError("exec", cid1, "ping", "-c", "1", cName) 688 c.Assert(err, check.NotNil) 689 _, _, err = dockerCmdWithError("exec", cid2, "ping", "-c", "1", cName) 690 c.Assert(err, check.NotNil) 691 } 692 693 func (s *DockerNetworkSuite) TestDockerNetworkLinkOndefaultNetworkOnly(c *check.C) { 694 // Link feature must work only on default network, and not across networks 695 cnt1 := "container1" 696 cnt2 := "container2" 697 network := "anotherbridge" 698 699 // Run first container on default network 700 dockerCmd(c, "run", "-d", "--name", cnt1, "busybox", "top") 701 702 // Create another network and run the second container on it 703 dockerCmd(c, "network", "create", network) 704 assertNwIsAvailable(c, network) 705 dockerCmd(c, "run", "-d", "--net", network, "--name", cnt2, "busybox", "top") 706 707 // Try launching a container on default network, linking to the first container. Must succeed 708 dockerCmd(c, "run", "-d", "--link", fmt.Sprintf("%s:%s", cnt1, cnt1), "busybox", "top") 709 710 // Try launching a container on default network, linking to the second container. Must fail 711 _, _, err := dockerCmdWithError("run", "-d", "--link", fmt.Sprintf("%s:%s", cnt2, cnt2), "busybox", "top") 712 c.Assert(err, checker.NotNil) 713 714 // Connect second container to default network. Now a container on default network can link to it 715 dockerCmd(c, "network", "connect", "bridge", cnt2) 716 dockerCmd(c, "run", "-d", "--link", fmt.Sprintf("%s:%s", cnt2, cnt2), "busybox", "top") 717 } 718 719 func (s *DockerNetworkSuite) TestDockerNetworkOverlayPortMapping(c *check.C) { 720 // Verify exposed ports are present in ps output when running a container on 721 // a network managed by a driver which does not provide the default gateway 722 // for the container 723 nwn := "ov" 724 ctn := "bb" 725 port1 := 80 726 port2 := 443 727 expose1 := fmt.Sprintf("--expose=%d", port1) 728 expose2 := fmt.Sprintf("--expose=%d", port2) 729 730 dockerCmd(c, "network", "create", "-d", dummyNetworkDriver, nwn) 731 assertNwIsAvailable(c, nwn) 732 733 dockerCmd(c, "run", "-d", "--net", nwn, "--name", ctn, expose1, expose2, "busybox", "top") 734 735 // Check docker ps o/p for last created container reports the unpublished ports 736 unpPort1 := fmt.Sprintf("%d/tcp", port1) 737 unpPort2 := fmt.Sprintf("%d/tcp", port2) 738 out, _ := dockerCmd(c, "ps", "-n=1") 739 // Missing unpublished ports in docker ps output 740 c.Assert(out, checker.Contains, unpPort1) 741 // Missing unpublished ports in docker ps output 742 c.Assert(out, checker.Contains, unpPort2) 743 } 744 745 func (s *DockerNetworkSuite) TestDockerNetworkMacInspect(c *check.C) { 746 // Verify endpoint MAC address is correctly populated in container's network settings 747 nwn := "ov" 748 ctn := "bb" 749 750 dockerCmd(c, "network", "create", "-d", dummyNetworkDriver, nwn) 751 assertNwIsAvailable(c, nwn) 752 753 dockerCmd(c, "run", "-d", "--net", nwn, "--name", ctn, "busybox", "top") 754 755 mac, err := inspectField(ctn, "NetworkSettings.Networks."+nwn+".MacAddress") 756 c.Assert(err, checker.IsNil) 757 c.Assert(mac, checker.Equals, "a0:b1:c2:d3:e4:f5") 758 } 759 760 func (s *DockerSuite) TestInspectApiMultipleNetworks(c *check.C) { 761 dockerCmd(c, "network", "create", "mybridge1") 762 dockerCmd(c, "network", "create", "mybridge2") 763 out, _ := dockerCmd(c, "run", "-d", "busybox", "top") 764 id := strings.TrimSpace(out) 765 c.Assert(waitRun(id), check.IsNil) 766 767 dockerCmd(c, "network", "connect", "mybridge1", id) 768 dockerCmd(c, "network", "connect", "mybridge2", id) 769 770 body := getInspectBody(c, "v1.20", id) 771 var inspect120 v1p20.ContainerJSON 772 err := json.Unmarshal(body, &inspect120) 773 c.Assert(err, checker.IsNil) 774 775 versionedIP := inspect120.NetworkSettings.IPAddress 776 777 body = getInspectBody(c, "v1.21", id) 778 var inspect121 types.ContainerJSON 779 err = json.Unmarshal(body, &inspect121) 780 c.Assert(err, checker.IsNil) 781 c.Assert(inspect121.NetworkSettings.Networks, checker.HasLen, 3) 782 783 bridge := inspect121.NetworkSettings.Networks["bridge"] 784 c.Assert(bridge.IPAddress, checker.Equals, versionedIP) 785 c.Assert(bridge.IPAddress, checker.Equals, inspect121.NetworkSettings.IPAddress) 786 } 787 788 func connectContainerToNetworks(c *check.C, d *Daemon, cName string, nws []string) { 789 // Run a container on the default network 790 out, err := d.Cmd("run", "-d", "--name", cName, "busybox", "top") 791 c.Assert(err, checker.IsNil, check.Commentf(out)) 792 793 // Attach the container to other three networks 794 for _, nw := range nws { 795 out, err = d.Cmd("network", "create", nw) 796 c.Assert(err, checker.IsNil, check.Commentf(out)) 797 out, err = d.Cmd("network", "connect", nw, cName) 798 c.Assert(err, checker.IsNil, check.Commentf(out)) 799 } 800 } 801 802 func verifyContainerIsConnectedToNetworks(c *check.C, d *Daemon, cName string, nws []string) { 803 // Verify container is connected to all three networks 804 for _, nw := range nws { 805 out, err := d.Cmd("inspect", "-f", fmt.Sprintf("{{.NetworkSettings.Networks.%s}}", nw), cName) 806 c.Assert(err, checker.IsNil, check.Commentf(out)) 807 c.Assert(out, checker.Not(checker.Equals), "<no value>\n") 808 } 809 } 810 811 func (s *DockerNetworkSuite) TestDockerNetworkMultipleNetworksGracefulDaemonRestart(c *check.C) { 812 cName := "bb" 813 nwList := []string{"nw1", "nw2", "nw3"} 814 815 s.d.StartWithBusybox() 816 817 connectContainerToNetworks(c, s.d, cName, nwList) 818 verifyContainerIsConnectedToNetworks(c, s.d, cName, nwList) 819 820 // Reload daemon 821 s.d.Restart() 822 823 _, err := s.d.Cmd("start", cName) 824 c.Assert(err, checker.IsNil) 825 826 verifyContainerIsConnectedToNetworks(c, s.d, cName, nwList) 827 } 828 829 func (s *DockerNetworkSuite) TestDockerNetworkMultipleNetworksUngracefulDaemonRestart(c *check.C) { 830 cName := "cc" 831 nwList := []string{"nw1", "nw2", "nw3"} 832 833 s.d.StartWithBusybox() 834 835 connectContainerToNetworks(c, s.d, cName, nwList) 836 verifyContainerIsConnectedToNetworks(c, s.d, cName, nwList) 837 838 // Kill daemon and restart 839 if err := s.d.cmd.Process.Kill(); err != nil { 840 c.Fatal(err) 841 } 842 s.d.Restart() 843 844 // Restart container 845 _, err := s.d.Cmd("start", cName) 846 c.Assert(err, checker.IsNil) 847 848 verifyContainerIsConnectedToNetworks(c, s.d, cName, nwList) 849 } 850 851 func (s *DockerNetworkSuite) TestDockerNetworkRunNetByID(c *check.C) { 852 out, _ := dockerCmd(c, "network", "create", "one") 853 dockerCmd(c, "run", "-d", "--net", strings.TrimSpace(out), "busybox", "top") 854 } 855 856 func (s *DockerNetworkSuite) TestDockerNetworkHostModeUngracefulDaemonRestart(c *check.C) { 857 testRequires(c, DaemonIsLinux, NotUserNamespace) 858 s.d.StartWithBusybox() 859 860 // Run a few containers on host network 861 for i := 0; i < 10; i++ { 862 cName := fmt.Sprintf("hostc-%d", i) 863 out, err := s.d.Cmd("run", "-d", "--name", cName, "--net=host", "--restart=always", "busybox", "top") 864 c.Assert(err, checker.IsNil, check.Commentf(out)) 865 } 866 867 // Kill daemon ungracefully and restart 868 if err := s.d.cmd.Process.Kill(); err != nil { 869 c.Fatal(err) 870 } 871 s.d.Restart() 872 873 // make sure all the containers are up and running 874 for i := 0; i < 10; i++ { 875 cName := fmt.Sprintf("hostc-%d", i) 876 runningOut, err := s.d.Cmd("inspect", "--format='{{.State.Running}}'", cName) 877 c.Assert(err, checker.IsNil) 878 c.Assert(strings.TrimSpace(runningOut), checker.Equals, "true") 879 } 880 } 881 882 func (s *DockerNetworkSuite) TestDockerNetworkConnectToHostFromOtherNetwork(c *check.C) { 883 dockerCmd(c, "run", "-d", "--name", "container1", "busybox", "top") 884 c.Assert(waitRun("container1"), check.IsNil) 885 dockerCmd(c, "network", "disconnect", "bridge", "container1") 886 out, _, err := dockerCmdWithError("network", "connect", "host", "container1") 887 c.Assert(err, checker.NotNil, check.Commentf(out)) 888 c.Assert(out, checker.Contains, runconfig.ErrConflictHostNetwork.Error()) 889 } 890 891 func (s *DockerNetworkSuite) TestDockerNetworkDisconnectFromHost(c *check.C) { 892 dockerCmd(c, "run", "-d", "--name", "container1", "--net=host", "busybox", "top") 893 c.Assert(waitRun("container1"), check.IsNil) 894 out, _, err := dockerCmdWithError("network", "disconnect", "host", "container1") 895 c.Assert(err, checker.NotNil, check.Commentf("Should err out disconnect from host")) 896 c.Assert(out, checker.Contains, runconfig.ErrConflictHostNetwork.Error()) 897 } 898 899 func (s *DockerNetworkSuite) TestDockerNetworkConnectWithPortMapping(c *check.C) { 900 dockerCmd(c, "network", "create", "test1") 901 dockerCmd(c, "run", "-d", "--name", "c1", "-p", "5000:5000", "busybox", "top") 902 c.Assert(waitRun("c1"), check.IsNil) 903 dockerCmd(c, "network", "connect", "test1", "c1") 904 } 905 906 func (s *DockerNetworkSuite) TestDockerNetworkConnectWithMac(c *check.C) { 907 macAddress := "02:42:ac:11:00:02" 908 dockerCmd(c, "network", "create", "mynetwork") 909 dockerCmd(c, "run", "--name=test", "-d", "--mac-address", macAddress, "busybox", "top") 910 c.Assert(waitRun("test"), check.IsNil) 911 mac1, err := inspectField("test", "NetworkSettings.Networks.bridge.MacAddress") 912 c.Assert(err, checker.IsNil) 913 c.Assert(strings.TrimSpace(mac1), checker.Equals, macAddress) 914 dockerCmd(c, "network", "connect", "mynetwork", "test") 915 mac2, err := inspectField("test", "NetworkSettings.Networks.mynetwork.MacAddress") 916 c.Assert(err, checker.IsNil) 917 c.Assert(strings.TrimSpace(mac2), checker.Not(checker.Equals), strings.TrimSpace(mac1)) 918 } 919 920 func (s *DockerNetworkSuite) TestDockerNetworkInspectCreatedContainer(c *check.C) { 921 dockerCmd(c, "create", "--name", "test", "busybox") 922 networks, err := inspectField("test", "NetworkSettings.Networks") 923 c.Assert(err, checker.IsNil) 924 c.Assert(networks, checker.Contains, "bridge", check.Commentf("Should return 'bridge' network")) 925 } 926 927 func (s *DockerNetworkSuite) TestDockerNetworkRestartWithMulipleNetworks(c *check.C) { 928 dockerCmd(c, "network", "create", "test") 929 dockerCmd(c, "run", "--name=foo", "-d", "busybox", "top") 930 c.Assert(waitRun("foo"), checker.IsNil) 931 dockerCmd(c, "network", "connect", "test", "foo") 932 dockerCmd(c, "restart", "foo") 933 networks, err := inspectField("foo", "NetworkSettings.Networks") 934 c.Assert(err, checker.IsNil) 935 c.Assert(networks, checker.Contains, "bridge", check.Commentf("Should contain 'bridge' network")) 936 c.Assert(networks, checker.Contains, "test", check.Commentf("Should contain 'test' network")) 937 } 938 939 func (s *DockerNetworkSuite) TestDockerNetworkConnectDisconnectToStoppedContainer(c *check.C) { 940 dockerCmd(c, "network", "create", "test") 941 dockerCmd(c, "create", "--name=foo", "busybox", "top") 942 dockerCmd(c, "network", "connect", "test", "foo") 943 networks, err := inspectField("foo", "NetworkSettings.Networks") 944 c.Assert(err, checker.IsNil) 945 c.Assert(networks, checker.Contains, "test", check.Commentf("Should contain 'test' network")) 946 947 // Restart docker daemon to test the config has persisted to disk 948 s.d.Restart() 949 networks, err = inspectField("foo", "NetworkSettings.Networks") 950 c.Assert(err, checker.IsNil) 951 c.Assert(networks, checker.Contains, "test", check.Commentf("Should contain 'test' network")) 952 953 // start the container and test if we can ping it from another container in the same network 954 dockerCmd(c, "start", "foo") 955 c.Assert(waitRun("foo"), checker.IsNil) 956 ip, err := inspectField("foo", "NetworkSettings.Networks.test.IPAddress") 957 ip = strings.TrimSpace(ip) 958 dockerCmd(c, "run", "--net=test", "busybox", "sh", "-c", fmt.Sprintf("ping -c 1 %s", ip)) 959 960 dockerCmd(c, "stop", "foo") 961 962 // Test disconnect 963 dockerCmd(c, "network", "disconnect", "test", "foo") 964 networks, err = inspectField("foo", "NetworkSettings.Networks") 965 c.Assert(err, checker.IsNil) 966 c.Assert(networks, checker.Not(checker.Contains), "test", check.Commentf("Should not contain 'test' network")) 967 968 // Restart docker daemon to test the config has persisted to disk 969 s.d.Restart() 970 networks, err = inspectField("foo", "NetworkSettings.Networks") 971 c.Assert(err, checker.IsNil) 972 c.Assert(networks, checker.Not(checker.Contains), "test", check.Commentf("Should not contain 'test' network")) 973 974 } 975 976 func (s *DockerNetworkSuite) TestDockerNetworkConnectPreferredIP(c *check.C) { 977 // create two networks 978 dockerCmd(c, "network", "create", "--subnet=172.28.0.0/16", "--subnet=2001:db8:1234::/64", "n0") 979 assertNwIsAvailable(c, "n0") 980 981 dockerCmd(c, "network", "create", "--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") 982 assertNwIsAvailable(c, "n1") 983 984 // run a container on first network specifying the ip addresses 985 dockerCmd(c, "run", "-d", "--name", "c0", "--net=n0", "--ip", "172.28.99.88", "--ip6", "2001:db8:1234::9988", "busybox", "top") 986 c.Assert(waitRun("c0"), check.IsNil) 987 verifyIPAddresses(c, "c0", "n0", "172.28.99.88", "2001:db8:1234::9988") 988 989 // connect the container to the second network specifying the preferred ip addresses 990 dockerCmd(c, "network", "connect", "--ip", "172.30.55.44", "--ip6", "2001:db8:abcd::5544", "n1", "c0") 991 verifyIPAddresses(c, "c0", "n1", "172.30.55.44", "2001:db8:abcd::5544") 992 993 // Stop and restart the container 994 dockerCmd(c, "stop", "c0") 995 dockerCmd(c, "start", "c0") 996 997 // verify preferred addresses are applied 998 verifyIPAddresses(c, "c0", "n0", "172.28.99.88", "2001:db8:1234::9988") 999 verifyIPAddresses(c, "c0", "n1", "172.30.55.44", "2001:db8:abcd::5544") 1000 1001 // Still it should fail to connect to the default network with a specified IP (whatever ip) 1002 out, _, err := dockerCmdWithError("network", "connect", "--ip", "172.21.55.44", "bridge", "c0") 1003 c.Assert(err, checker.NotNil, check.Commentf("out: %s", out)) 1004 c.Assert(out, checker.Contains, runconfig.ErrUnsupportedNetworkAndIP.Error()) 1005 1006 } 1007 1008 func (s *DockerNetworkSuite) TestDockerNetworkUnsupportedPreferredIP(c *check.C) { 1009 // preferred IP is not supported on predefined networks 1010 for _, mode := range []string{"none", "host", "bridge"} { 1011 checkUnsupportedNetworkAndIP(c, mode) 1012 } 1013 1014 // preferred IP is not supported on networks with no user defined subnets 1015 dockerCmd(c, "network", "create", "n0") 1016 assertNwIsAvailable(c, "n0") 1017 1018 out, _, err := dockerCmdWithError("run", "-d", "--ip", "172.28.99.88", "--net", "n0", "busybox", "top") 1019 c.Assert(err, checker.NotNil, check.Commentf("out: %s", out)) 1020 c.Assert(out, checker.Contains, runconfig.ErrUnsupportedNetworkNoSubnetAndIP.Error()) 1021 1022 out, _, err = dockerCmdWithError("run", "-d", "--ip6", "2001:db8:1234::9988", "--net", "n0", "busybox", "top") 1023 c.Assert(err, checker.NotNil, check.Commentf("out: %s", out)) 1024 c.Assert(out, checker.Contains, runconfig.ErrUnsupportedNetworkNoSubnetAndIP.Error()) 1025 1026 dockerCmd(c, "network", "rm", "n0") 1027 assertNwNotAvailable(c, "n0") 1028 } 1029 1030 func checkUnsupportedNetworkAndIP(c *check.C, nwMode string) { 1031 out, _, err := dockerCmdWithError("run", "-d", "--net", nwMode, "--ip", "172.28.99.88", "--ip6", "2001:db8:1234::9988", "busybox", "top") 1032 c.Assert(err, checker.NotNil, check.Commentf("out: %s", out)) 1033 c.Assert(out, checker.Contains, runconfig.ErrUnsupportedNetworkAndIP.Error()) 1034 } 1035 1036 func verifyIPAddresses(c *check.C, cName, nwname, ipv4, ipv6 string) { 1037 out, _ := dockerCmd(c, "inspect", fmt.Sprintf("--format='{{ .NetworkSettings.Networks.%s.IPAddress }}'", nwname), cName) 1038 c.Assert(strings.TrimSpace(out), check.Equals, ipv4) 1039 1040 out, _ = dockerCmd(c, "inspect", fmt.Sprintf("--format='{{ .NetworkSettings.Networks.%s.GlobalIPv6Address }}'", nwname), cName) 1041 c.Assert(strings.TrimSpace(out), check.Equals, ipv6) 1042 } 1043 1044 func (s *DockerSuite) TestUserDefinedNetworkConnectDisconnectLink(c *check.C) { 1045 testRequires(c, DaemonIsLinux, NotUserNamespace) 1046 dockerCmd(c, "network", "create", "-d", "bridge", "foo1") 1047 dockerCmd(c, "network", "create", "-d", "bridge", "foo2") 1048 1049 dockerCmd(c, "run", "-d", "--net=foo1", "--name=first", "busybox", "top") 1050 c.Assert(waitRun("first"), check.IsNil) 1051 1052 // run a container in user-defined network udlinkNet with a link for an existing container 1053 // and a link for a container that doesnt exist 1054 dockerCmd(c, "run", "-d", "--net=foo1", "--name=second", "--link=first:FirstInFoo1", 1055 "--link=third:bar", "busybox", "top") 1056 c.Assert(waitRun("second"), check.IsNil) 1057 1058 // ping to first and its alias FirstInFoo1 must succeed 1059 _, _, err := dockerCmdWithError("exec", "second", "ping", "-c", "1", "first") 1060 c.Assert(err, check.IsNil) 1061 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "FirstInFoo1") 1062 c.Assert(err, check.IsNil) 1063 1064 // connect first container to foo2 network 1065 dockerCmd(c, "network", "connect", "foo2", "first") 1066 // connect second container to foo2 network with a different alias for first container 1067 dockerCmd(c, "network", "connect", "--link=first:FirstInFoo2", "foo2", "second") 1068 1069 // ping the new alias in network foo2 1070 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "FirstInFoo2") 1071 c.Assert(err, check.IsNil) 1072 1073 // disconnect first container from foo1 network 1074 dockerCmd(c, "network", "disconnect", "foo1", "first") 1075 1076 // link in foo1 network must fail 1077 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "FirstInFoo1") 1078 c.Assert(err, check.NotNil) 1079 1080 // link in foo2 network must succeed 1081 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "FirstInFoo2") 1082 c.Assert(err, check.IsNil) 1083 }