github.com/vincentwoo/docker@v0.7.3-0.20160116130405-82401a4b13c0/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 networkID := 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="+networkID[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 containerID := strings.TrimSpace(out) 328 waitRun(containerID) 329 330 // delete three networks at the same time, since testDelMulti2 331 // contains active container, its deletion should fail. 332 out, _, err := dockerCmdWithError("network", "rm", "testDelMulti0", "testDelMulti1", "testDelMulti2") 333 // err should not be nil due to deleting testDelMulti2 failed. 334 c.Assert(err, checker.NotNil, check.Commentf("out: %s", out)) 335 // testDelMulti2 should fail due to network has active endpoints 336 c.Assert(out, checker.Contains, "has active endpoints") 337 assertNwNotAvailable(c, "testDelMulti0") 338 assertNwNotAvailable(c, "testDelMulti1") 339 // testDelMulti2 can't be deleted, so it should exist 340 assertNwIsAvailable(c, "testDelMulti2") 341 } 342 343 func (s *DockerSuite) TestDockerNetworkInspect(c *check.C) { 344 out, _ := dockerCmd(c, "network", "inspect", "host") 345 networkResources := []types.NetworkResource{} 346 err := json.Unmarshal([]byte(out), &networkResources) 347 c.Assert(err, check.IsNil) 348 c.Assert(networkResources, checker.HasLen, 1) 349 350 out, _ = dockerCmd(c, "network", "inspect", "--format='{{ .Name }}'", "host") 351 c.Assert(strings.TrimSpace(out), check.Equals, "host") 352 } 353 354 func (s *DockerSuite) TestDockerInspectMultipleNetwork(c *check.C) { 355 out, _ := dockerCmd(c, "network", "inspect", "host", "none") 356 networkResources := []types.NetworkResource{} 357 err := json.Unmarshal([]byte(out), &networkResources) 358 c.Assert(err, check.IsNil) 359 c.Assert(networkResources, checker.HasLen, 2) 360 361 // Should print an error, return an exitCode 1 *but* should print the host network 362 out, exitCode, err := dockerCmdWithError("network", "inspect", "host", "nonexistent") 363 c.Assert(err, checker.NotNil) 364 c.Assert(exitCode, checker.Equals, 1) 365 c.Assert(out, checker.Contains, "Error: No such network: nonexistent") 366 networkResources = []types.NetworkResource{} 367 inspectOut := strings.SplitN(out, "\nError: No such network: nonexistent\n", 2)[0] 368 err = json.Unmarshal([]byte(inspectOut), &networkResources) 369 c.Assert(networkResources, checker.HasLen, 1) 370 371 // Should print an error and return an exitCode, nothing else 372 out, exitCode, err = dockerCmdWithError("network", "inspect", "nonexistent") 373 c.Assert(err, checker.NotNil) 374 c.Assert(exitCode, checker.Equals, 1) 375 c.Assert(out, checker.Contains, "Error: No such network: nonexistent") 376 } 377 378 func (s *DockerSuite) TestDockerInspectNetworkWithContainerName(c *check.C) { 379 dockerCmd(c, "network", "create", "brNetForInspect") 380 assertNwIsAvailable(c, "brNetForInspect") 381 defer func() { 382 dockerCmd(c, "network", "rm", "brNetForInspect") 383 assertNwNotAvailable(c, "brNetForInspect") 384 }() 385 386 out, _ := dockerCmd(c, "run", "-d", "--name", "testNetInspect1", "--net", "brNetForInspect", "busybox", "top") 387 c.Assert(waitRun("testNetInspect1"), check.IsNil) 388 containerID := strings.TrimSpace(out) 389 defer func() { 390 // we don't stop container by name, because we'll rename it later 391 dockerCmd(c, "stop", containerID) 392 }() 393 394 out, _ = dockerCmd(c, "network", "inspect", "brNetForInspect") 395 networkResources := []types.NetworkResource{} 396 err := json.Unmarshal([]byte(out), &networkResources) 397 c.Assert(err, check.IsNil) 398 c.Assert(networkResources, checker.HasLen, 1) 399 container, ok := networkResources[0].Containers[containerID] 400 c.Assert(ok, checker.True) 401 c.Assert(container.Name, checker.Equals, "testNetInspect1") 402 403 // rename container and check docker inspect output update 404 newName := "HappyNewName" 405 dockerCmd(c, "rename", "testNetInspect1", newName) 406 407 // check whether network inspect works properly 408 out, _ = dockerCmd(c, "network", "inspect", "brNetForInspect") 409 newNetRes := []types.NetworkResource{} 410 err = json.Unmarshal([]byte(out), &newNetRes) 411 c.Assert(err, check.IsNil) 412 c.Assert(newNetRes, checker.HasLen, 1) 413 container1, ok := newNetRes[0].Containers[containerID] 414 c.Assert(ok, checker.True) 415 c.Assert(container1.Name, checker.Equals, newName) 416 417 } 418 419 func (s *DockerNetworkSuite) TestDockerNetworkConnectDisconnect(c *check.C) { 420 dockerCmd(c, "network", "create", "test") 421 assertNwIsAvailable(c, "test") 422 nr := getNwResource(c, "test") 423 424 c.Assert(nr.Name, checker.Equals, "test") 425 c.Assert(len(nr.Containers), checker.Equals, 0) 426 427 // run a container 428 out, _ := dockerCmd(c, "run", "-d", "--name", "test", "busybox", "top") 429 c.Assert(waitRun("test"), check.IsNil) 430 containerID := strings.TrimSpace(out) 431 432 // connect the container to the test network 433 dockerCmd(c, "network", "connect", "test", containerID) 434 435 // inspect the network to make sure container is connected 436 nr = getNetworkResource(c, nr.ID) 437 c.Assert(len(nr.Containers), checker.Equals, 1) 438 c.Assert(nr.Containers[containerID], check.NotNil) 439 440 // check if container IP matches network inspect 441 ip, _, err := net.ParseCIDR(nr.Containers[containerID].IPv4Address) 442 c.Assert(err, check.IsNil) 443 containerIP := findContainerIP(c, "test", "test") 444 c.Assert(ip.String(), checker.Equals, containerIP) 445 446 // disconnect container from the network 447 dockerCmd(c, "network", "disconnect", "test", containerID) 448 nr = getNwResource(c, "test") 449 c.Assert(nr.Name, checker.Equals, "test") 450 c.Assert(len(nr.Containers), checker.Equals, 0) 451 452 // run another container 453 out, _ = dockerCmd(c, "run", "-d", "--net", "test", "--name", "test2", "busybox", "top") 454 c.Assert(waitRun("test2"), check.IsNil) 455 containerID = strings.TrimSpace(out) 456 457 nr = getNwResource(c, "test") 458 c.Assert(nr.Name, checker.Equals, "test") 459 c.Assert(len(nr.Containers), checker.Equals, 1) 460 461 // force disconnect the container to the test network 462 dockerCmd(c, "network", "disconnect", "-f", "test", containerID) 463 464 nr = getNwResource(c, "test") 465 c.Assert(nr.Name, checker.Equals, "test") 466 c.Assert(len(nr.Containers), checker.Equals, 0) 467 468 dockerCmd(c, "network", "rm", "test") 469 assertNwNotAvailable(c, "test") 470 } 471 472 func (s *DockerNetworkSuite) TestDockerNetworkIpamMultipleNetworks(c *check.C) { 473 // test0 bridge network 474 dockerCmd(c, "network", "create", "--subnet=192.168.0.0/16", "test1") 475 assertNwIsAvailable(c, "test1") 476 477 // test2 bridge network does not overlap 478 dockerCmd(c, "network", "create", "--subnet=192.169.0.0/16", "test2") 479 assertNwIsAvailable(c, "test2") 480 481 // for networks w/o ipam specified, docker will choose proper non-overlapping subnets 482 dockerCmd(c, "network", "create", "test3") 483 assertNwIsAvailable(c, "test3") 484 dockerCmd(c, "network", "create", "test4") 485 assertNwIsAvailable(c, "test4") 486 dockerCmd(c, "network", "create", "test5") 487 assertNwIsAvailable(c, "test5") 488 489 // test network with multiple subnets 490 // bridge network doesn't support multiple subnets. hence, use a dummy driver that supports 491 492 dockerCmd(c, "network", "create", "-d", dummyNetworkDriver, "--subnet=192.168.0.0/16", "--subnet=192.170.0.0/16", "test6") 493 assertNwIsAvailable(c, "test6") 494 495 // test network with multiple subnets with valid ipam combinations 496 // also check same subnet across networks when the driver supports it. 497 dockerCmd(c, "network", "create", "-d", dummyNetworkDriver, 498 "--subnet=192.168.0.0/16", "--subnet=192.170.0.0/16", 499 "--gateway=192.168.0.100", "--gateway=192.170.0.100", 500 "--ip-range=192.168.1.0/24", 501 "--aux-address", "a=192.168.1.5", "--aux-address", "b=192.168.1.6", 502 "--aux-address", "a=192.170.1.5", "--aux-address", "b=192.170.1.6", 503 "test7") 504 assertNwIsAvailable(c, "test7") 505 506 // cleanup 507 for i := 1; i < 8; i++ { 508 dockerCmd(c, "network", "rm", fmt.Sprintf("test%d", i)) 509 } 510 } 511 512 func (s *DockerNetworkSuite) TestDockerNetworkCustomIpam(c *check.C) { 513 // Create a bridge network using custom ipam driver 514 dockerCmd(c, "network", "create", "--ipam-driver", dummyIpamDriver, "br0") 515 assertNwIsAvailable(c, "br0") 516 517 // Verify expected network ipam fields are there 518 nr := getNetworkResource(c, "br0") 519 c.Assert(nr.Driver, checker.Equals, "bridge") 520 c.Assert(nr.IPAM.Driver, checker.Equals, dummyIpamDriver) 521 522 // remove network and exercise remote ipam driver 523 dockerCmd(c, "network", "rm", "br0") 524 assertNwNotAvailable(c, "br0") 525 } 526 527 func (s *DockerNetworkSuite) TestDockerNetworkIpamOptions(c *check.C) { 528 // Create a bridge network using custom ipam driver and options 529 dockerCmd(c, "network", "create", "--ipam-driver", dummyIpamDriver, "--ipam-opt", "opt1=drv1", "--ipam-opt", "opt2=drv2", "br0") 530 assertNwIsAvailable(c, "br0") 531 532 // Verify expected network ipam options 533 nr := getNetworkResource(c, "br0") 534 opts := nr.IPAM.Options 535 c.Assert(opts["opt1"], checker.Equals, "drv1") 536 c.Assert(opts["opt2"], checker.Equals, "drv2") 537 } 538 539 func (s *DockerNetworkSuite) TestDockerNetworkInspectDefault(c *check.C) { 540 nr := getNetworkResource(c, "none") 541 c.Assert(nr.Driver, checker.Equals, "null") 542 c.Assert(nr.Scope, checker.Equals, "local") 543 c.Assert(nr.IPAM.Driver, checker.Equals, "default") 544 c.Assert(len(nr.IPAM.Config), checker.Equals, 0) 545 546 nr = getNetworkResource(c, "host") 547 c.Assert(nr.Driver, checker.Equals, "host") 548 c.Assert(nr.Scope, checker.Equals, "local") 549 c.Assert(nr.IPAM.Driver, checker.Equals, "default") 550 c.Assert(len(nr.IPAM.Config), checker.Equals, 0) 551 552 nr = getNetworkResource(c, "bridge") 553 c.Assert(nr.Driver, checker.Equals, "bridge") 554 c.Assert(nr.Scope, checker.Equals, "local") 555 c.Assert(nr.IPAM.Driver, checker.Equals, "default") 556 c.Assert(len(nr.IPAM.Config), checker.Equals, 1) 557 c.Assert(nr.IPAM.Config[0].Subnet, checker.NotNil) 558 c.Assert(nr.IPAM.Config[0].Gateway, checker.NotNil) 559 } 560 561 func (s *DockerNetworkSuite) TestDockerNetworkInspectCustomUnspecified(c *check.C) { 562 // if unspecified, network subnet will be selected from inside preferred pool 563 dockerCmd(c, "network", "create", "test01") 564 assertNwIsAvailable(c, "test01") 565 566 nr := getNetworkResource(c, "test01") 567 c.Assert(nr.Driver, checker.Equals, "bridge") 568 c.Assert(nr.Scope, checker.Equals, "local") 569 c.Assert(nr.IPAM.Driver, checker.Equals, "default") 570 c.Assert(len(nr.IPAM.Config), checker.Equals, 1) 571 c.Assert(nr.IPAM.Config[0].Subnet, checker.NotNil) 572 c.Assert(nr.IPAM.Config[0].Gateway, checker.NotNil) 573 574 dockerCmd(c, "network", "rm", "test01") 575 assertNwNotAvailable(c, "test01") 576 } 577 578 func (s *DockerNetworkSuite) TestDockerNetworkInspectCustomSpecified(c *check.C) { 579 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") 580 assertNwIsAvailable(c, "br0") 581 582 nr := getNetworkResource(c, "br0") 583 c.Assert(nr.Driver, checker.Equals, "bridge") 584 c.Assert(nr.Scope, checker.Equals, "local") 585 c.Assert(nr.IPAM.Driver, checker.Equals, "default") 586 c.Assert(len(nr.IPAM.Config), checker.Equals, 1) 587 c.Assert(nr.IPAM.Config[0].Subnet, checker.Equals, "172.28.0.0/16") 588 c.Assert(nr.IPAM.Config[0].IPRange, checker.Equals, "172.28.5.0/24") 589 c.Assert(nr.IPAM.Config[0].Gateway, checker.Equals, "172.28.5.254") 590 dockerCmd(c, "network", "rm", "br0") 591 assertNwNotAvailable(c, "test01") 592 } 593 594 func (s *DockerNetworkSuite) TestDockerNetworkIpamInvalidCombinations(c *check.C) { 595 // network with ip-range out of subnet range 596 _, _, err := dockerCmdWithError("network", "create", "--subnet=192.168.0.0/16", "--ip-range=192.170.0.0/16", "test") 597 c.Assert(err, check.NotNil) 598 599 // network with multiple gateways for a single subnet 600 _, _, err = dockerCmdWithError("network", "create", "--subnet=192.168.0.0/16", "--gateway=192.168.0.1", "--gateway=192.168.0.2", "test") 601 c.Assert(err, check.NotNil) 602 603 // Multiple overlapping subnets in the same network must fail 604 _, _, err = dockerCmdWithError("network", "create", "--subnet=192.168.0.0/16", "--subnet=192.168.1.0/16", "test") 605 c.Assert(err, check.NotNil) 606 607 // overlapping subnets across networks must fail 608 // create a valid test0 network 609 dockerCmd(c, "network", "create", "--subnet=192.168.0.0/16", "test0") 610 assertNwIsAvailable(c, "test0") 611 // create an overlapping test1 network 612 _, _, err = dockerCmdWithError("network", "create", "--subnet=192.168.128.0/17", "test1") 613 c.Assert(err, check.NotNil) 614 dockerCmd(c, "network", "rm", "test0") 615 assertNwNotAvailable(c, "test0") 616 } 617 618 func (s *DockerNetworkSuite) TestDockerNetworkDriverOptions(c *check.C) { 619 dockerCmd(c, "network", "create", "-d", dummyNetworkDriver, "-o", "opt1=drv1", "-o", "opt2=drv2", "testopt") 620 assertNwIsAvailable(c, "testopt") 621 gopts := remoteDriverNetworkRequest.Options[netlabel.GenericData] 622 c.Assert(gopts, checker.NotNil) 623 opts, ok := gopts.(map[string]interface{}) 624 c.Assert(ok, checker.Equals, true) 625 c.Assert(opts["opt1"], checker.Equals, "drv1") 626 c.Assert(opts["opt2"], checker.Equals, "drv2") 627 dockerCmd(c, "network", "rm", "testopt") 628 assertNwNotAvailable(c, "testopt") 629 630 } 631 632 func (s *DockerDaemonSuite) TestDockerNetworkNoDiscoveryDefaultBridgeNetwork(c *check.C) { 633 testRequires(c, ExecSupport) 634 // On default bridge network built-in service discovery should not happen 635 hostsFile := "/etc/hosts" 636 bridgeName := "external-bridge" 637 bridgeIP := "192.169.255.254/24" 638 out, err := createInterface(c, "bridge", bridgeName, bridgeIP) 639 c.Assert(err, check.IsNil, check.Commentf(out)) 640 defer deleteInterface(c, bridgeName) 641 642 err = s.d.StartWithBusybox("--bridge", bridgeName) 643 c.Assert(err, check.IsNil) 644 defer s.d.Restart() 645 646 // run two containers and store first container's etc/hosts content 647 out, err = s.d.Cmd("run", "-d", "busybox", "top") 648 c.Assert(err, check.IsNil) 649 cid1 := strings.TrimSpace(out) 650 defer s.d.Cmd("stop", cid1) 651 652 hosts, err := s.d.Cmd("exec", cid1, "cat", hostsFile) 653 c.Assert(err, checker.IsNil) 654 655 out, err = s.d.Cmd("run", "-d", "--name", "container2", "busybox", "top") 656 c.Assert(err, check.IsNil) 657 cid2 := strings.TrimSpace(out) 658 659 // verify first container's etc/hosts file has not changed after spawning the second named container 660 hostsPost, err := s.d.Cmd("exec", cid1, "cat", hostsFile) 661 c.Assert(err, checker.IsNil) 662 c.Assert(string(hosts), checker.Equals, string(hostsPost), 663 check.Commentf("Unexpected %s change on second container creation", hostsFile)) 664 665 // stop container 2 and verify first container's etc/hosts has not changed 666 _, err = s.d.Cmd("stop", cid2) 667 c.Assert(err, check.IsNil) 668 669 hostsPost, err = s.d.Cmd("exec", cid1, "cat", hostsFile) 670 c.Assert(err, checker.IsNil) 671 c.Assert(string(hosts), checker.Equals, string(hostsPost), 672 check.Commentf("Unexpected %s change on second container creation", hostsFile)) 673 674 // but discovery is on when connecting to non default bridge network 675 network := "anotherbridge" 676 out, err = s.d.Cmd("network", "create", network) 677 c.Assert(err, check.IsNil, check.Commentf(out)) 678 defer s.d.Cmd("network", "rm", network) 679 680 out, err = s.d.Cmd("network", "connect", network, cid1) 681 c.Assert(err, check.IsNil, check.Commentf(out)) 682 683 hosts, err = s.d.Cmd("exec", cid1, "cat", hostsFile) 684 c.Assert(err, checker.IsNil) 685 686 hostsPost, err = s.d.Cmd("exec", cid1, "cat", hostsFile) 687 c.Assert(err, checker.IsNil) 688 c.Assert(string(hosts), checker.Equals, string(hostsPost), 689 check.Commentf("Unexpected %s change on second network connection", hostsFile)) 690 } 691 692 func (s *DockerNetworkSuite) TestDockerNetworkAnonymousEndpoint(c *check.C) { 693 testRequires(c, ExecSupport) 694 hostsFile := "/etc/hosts" 695 cstmBridgeNw := "custom-bridge-nw" 696 cstmBridgeNw1 := "custom-bridge-nw1" 697 698 dockerCmd(c, "network", "create", "-d", "bridge", cstmBridgeNw) 699 assertNwIsAvailable(c, cstmBridgeNw) 700 701 // run two anonymous containers and store their etc/hosts content 702 out, _ := dockerCmd(c, "run", "-d", "--net", cstmBridgeNw, "busybox", "top") 703 cid1 := strings.TrimSpace(out) 704 705 hosts1, err := readContainerFileWithExec(cid1, hostsFile) 706 c.Assert(err, checker.IsNil) 707 708 out, _ = dockerCmd(c, "run", "-d", "--net", cstmBridgeNw, "busybox", "top") 709 cid2 := strings.TrimSpace(out) 710 711 hosts2, err := readContainerFileWithExec(cid2, hostsFile) 712 c.Assert(err, checker.IsNil) 713 714 // verify first container etc/hosts file has not changed 715 hosts1post, err := readContainerFileWithExec(cid1, hostsFile) 716 c.Assert(err, checker.IsNil) 717 c.Assert(string(hosts1), checker.Equals, string(hosts1post), 718 check.Commentf("Unexpected %s change on anonymous container creation", hostsFile)) 719 720 // Connect the 2nd container to a new network and verify the 721 // first container /etc/hosts file still hasn't changed. 722 dockerCmd(c, "network", "create", "-d", "bridge", cstmBridgeNw1) 723 assertNwIsAvailable(c, cstmBridgeNw1) 724 725 dockerCmd(c, "network", "connect", cstmBridgeNw1, cid2) 726 727 hosts2, err = readContainerFileWithExec(cid2, hostsFile) 728 c.Assert(err, checker.IsNil) 729 730 hosts1post, err = readContainerFileWithExec(cid1, hostsFile) 731 c.Assert(err, checker.IsNil) 732 c.Assert(string(hosts1), checker.Equals, string(hosts1post), 733 check.Commentf("Unexpected %s change on container connect", hostsFile)) 734 735 // start a named container 736 cName := "AnyName" 737 out, _ = dockerCmd(c, "run", "-d", "--net", cstmBridgeNw, "--name", cName, "busybox", "top") 738 cid3 := strings.TrimSpace(out) 739 740 // verify that container 1 and 2 can ping the named container 741 dockerCmd(c, "exec", cid1, "ping", "-c", "1", cName) 742 dockerCmd(c, "exec", cid2, "ping", "-c", "1", cName) 743 744 // Stop named container and verify first two containers' etc/hosts file hasn't changed 745 dockerCmd(c, "stop", cid3) 746 hosts1post, err = readContainerFileWithExec(cid1, hostsFile) 747 c.Assert(err, checker.IsNil) 748 c.Assert(string(hosts1), checker.Equals, string(hosts1post), 749 check.Commentf("Unexpected %s change on name container creation", hostsFile)) 750 751 hosts2post, err := readContainerFileWithExec(cid2, hostsFile) 752 c.Assert(err, checker.IsNil) 753 c.Assert(string(hosts2), checker.Equals, string(hosts2post), 754 check.Commentf("Unexpected %s change on name container creation", hostsFile)) 755 756 // verify that container 1 and 2 can't ping the named container now 757 _, _, err = dockerCmdWithError("exec", cid1, "ping", "-c", "1", cName) 758 c.Assert(err, check.NotNil) 759 _, _, err = dockerCmdWithError("exec", cid2, "ping", "-c", "1", cName) 760 c.Assert(err, check.NotNil) 761 } 762 763 func (s *DockerNetworkSuite) TestDockerNetworkLinkOndefaultNetworkOnly(c *check.C) { 764 // Link feature must work only on default network, and not across networks 765 cnt1 := "container1" 766 cnt2 := "container2" 767 network := "anotherbridge" 768 769 // Run first container on default network 770 dockerCmd(c, "run", "-d", "--name", cnt1, "busybox", "top") 771 772 // Create another network and run the second container on it 773 dockerCmd(c, "network", "create", network) 774 assertNwIsAvailable(c, network) 775 dockerCmd(c, "run", "-d", "--net", network, "--name", cnt2, "busybox", "top") 776 777 // Try launching a container on default network, linking to the first container. Must succeed 778 dockerCmd(c, "run", "-d", "--link", fmt.Sprintf("%s:%s", cnt1, cnt1), "busybox", "top") 779 780 // Try launching a container on default network, linking to the second container. Must fail 781 _, _, err := dockerCmdWithError("run", "-d", "--link", fmt.Sprintf("%s:%s", cnt2, cnt2), "busybox", "top") 782 c.Assert(err, checker.NotNil) 783 784 // Connect second container to default network. Now a container on default network can link to it 785 dockerCmd(c, "network", "connect", "bridge", cnt2) 786 dockerCmd(c, "run", "-d", "--link", fmt.Sprintf("%s:%s", cnt2, cnt2), "busybox", "top") 787 } 788 789 func (s *DockerNetworkSuite) TestDockerNetworkOverlayPortMapping(c *check.C) { 790 // Verify exposed ports are present in ps output when running a container on 791 // a network managed by a driver which does not provide the default gateway 792 // for the container 793 nwn := "ov" 794 ctn := "bb" 795 port1 := 80 796 port2 := 443 797 expose1 := fmt.Sprintf("--expose=%d", port1) 798 expose2 := fmt.Sprintf("--expose=%d", port2) 799 800 dockerCmd(c, "network", "create", "-d", dummyNetworkDriver, nwn) 801 assertNwIsAvailable(c, nwn) 802 803 dockerCmd(c, "run", "-d", "--net", nwn, "--name", ctn, expose1, expose2, "busybox", "top") 804 805 // Check docker ps o/p for last created container reports the unpublished ports 806 unpPort1 := fmt.Sprintf("%d/tcp", port1) 807 unpPort2 := fmt.Sprintf("%d/tcp", port2) 808 out, _ := dockerCmd(c, "ps", "-n=1") 809 // Missing unpublished ports in docker ps output 810 c.Assert(out, checker.Contains, unpPort1) 811 // Missing unpublished ports in docker ps output 812 c.Assert(out, checker.Contains, unpPort2) 813 } 814 815 func (s *DockerNetworkSuite) TestDockerNetworkMacInspect(c *check.C) { 816 // Verify endpoint MAC address is correctly populated in container's network settings 817 nwn := "ov" 818 ctn := "bb" 819 820 dockerCmd(c, "network", "create", "-d", dummyNetworkDriver, nwn) 821 assertNwIsAvailable(c, nwn) 822 823 dockerCmd(c, "run", "-d", "--net", nwn, "--name", ctn, "busybox", "top") 824 825 mac, err := inspectField(ctn, "NetworkSettings.Networks."+nwn+".MacAddress") 826 c.Assert(err, checker.IsNil) 827 c.Assert(mac, checker.Equals, "a0:b1:c2:d3:e4:f5") 828 } 829 830 func (s *DockerSuite) TestInspectApiMultipleNetworks(c *check.C) { 831 dockerCmd(c, "network", "create", "mybridge1") 832 dockerCmd(c, "network", "create", "mybridge2") 833 out, _ := dockerCmd(c, "run", "-d", "busybox", "top") 834 id := strings.TrimSpace(out) 835 c.Assert(waitRun(id), check.IsNil) 836 837 dockerCmd(c, "network", "connect", "mybridge1", id) 838 dockerCmd(c, "network", "connect", "mybridge2", id) 839 840 body := getInspectBody(c, "v1.20", id) 841 var inspect120 v1p20.ContainerJSON 842 err := json.Unmarshal(body, &inspect120) 843 c.Assert(err, checker.IsNil) 844 845 versionedIP := inspect120.NetworkSettings.IPAddress 846 847 body = getInspectBody(c, "v1.21", id) 848 var inspect121 types.ContainerJSON 849 err = json.Unmarshal(body, &inspect121) 850 c.Assert(err, checker.IsNil) 851 c.Assert(inspect121.NetworkSettings.Networks, checker.HasLen, 3) 852 853 bridge := inspect121.NetworkSettings.Networks["bridge"] 854 c.Assert(bridge.IPAddress, checker.Equals, versionedIP) 855 c.Assert(bridge.IPAddress, checker.Equals, inspect121.NetworkSettings.IPAddress) 856 } 857 858 func connectContainerToNetworks(c *check.C, d *Daemon, cName string, nws []string) { 859 // Run a container on the default network 860 out, err := d.Cmd("run", "-d", "--name", cName, "busybox", "top") 861 c.Assert(err, checker.IsNil, check.Commentf(out)) 862 863 // Attach the container to other networks 864 for _, nw := range nws { 865 out, err = d.Cmd("network", "create", nw) 866 c.Assert(err, checker.IsNil, check.Commentf(out)) 867 out, err = d.Cmd("network", "connect", nw, cName) 868 c.Assert(err, checker.IsNil, check.Commentf(out)) 869 } 870 } 871 872 func verifyContainerIsConnectedToNetworks(c *check.C, d *Daemon, cName string, nws []string) { 873 // Verify container is connected to all the networks 874 for _, nw := range nws { 875 out, err := d.Cmd("inspect", "-f", fmt.Sprintf("{{.NetworkSettings.Networks.%s}}", nw), cName) 876 c.Assert(err, checker.IsNil, check.Commentf(out)) 877 c.Assert(out, checker.Not(checker.Equals), "<no value>\n") 878 } 879 } 880 881 func (s *DockerNetworkSuite) TestDockerNetworkMultipleNetworksGracefulDaemonRestart(c *check.C) { 882 cName := "bb" 883 nwList := []string{"nw1", "nw2", "nw3"} 884 885 s.d.StartWithBusybox() 886 887 connectContainerToNetworks(c, s.d, cName, nwList) 888 verifyContainerIsConnectedToNetworks(c, s.d, cName, nwList) 889 890 // Reload daemon 891 s.d.Restart() 892 893 _, err := s.d.Cmd("start", cName) 894 c.Assert(err, checker.IsNil) 895 896 verifyContainerIsConnectedToNetworks(c, s.d, cName, nwList) 897 } 898 899 func (s *DockerNetworkSuite) TestDockerNetworkMultipleNetworksUngracefulDaemonRestart(c *check.C) { 900 cName := "cc" 901 nwList := []string{"nw1", "nw2", "nw3"} 902 903 s.d.StartWithBusybox() 904 905 connectContainerToNetworks(c, s.d, cName, nwList) 906 verifyContainerIsConnectedToNetworks(c, s.d, cName, nwList) 907 908 // Kill daemon and restart 909 if err := s.d.cmd.Process.Kill(); err != nil { 910 c.Fatal(err) 911 } 912 s.d.Restart() 913 914 // Restart container 915 _, err := s.d.Cmd("start", cName) 916 c.Assert(err, checker.IsNil) 917 918 verifyContainerIsConnectedToNetworks(c, s.d, cName, nwList) 919 } 920 921 func (s *DockerNetworkSuite) TestDockerNetworkRunNetByID(c *check.C) { 922 out, _ := dockerCmd(c, "network", "create", "one") 923 containerOut, _, err := dockerCmdWithError("run", "-d", "--net", strings.TrimSpace(out), "busybox", "top") 924 c.Assert(err, checker.IsNil, check.Commentf(containerOut)) 925 } 926 927 func (s *DockerNetworkSuite) TestDockerNetworkHostModeUngracefulDaemonRestart(c *check.C) { 928 testRequires(c, DaemonIsLinux, NotUserNamespace) 929 s.d.StartWithBusybox() 930 931 // Run a few containers on host network 932 for i := 0; i < 10; i++ { 933 cName := fmt.Sprintf("hostc-%d", i) 934 out, err := s.d.Cmd("run", "-d", "--name", cName, "--net=host", "--restart=always", "busybox", "top") 935 c.Assert(err, checker.IsNil, check.Commentf(out)) 936 } 937 938 // Kill daemon ungracefully and restart 939 if err := s.d.cmd.Process.Kill(); err != nil { 940 c.Fatal(err) 941 } 942 s.d.Restart() 943 944 // make sure all the containers are up and running 945 for i := 0; i < 10; i++ { 946 cName := fmt.Sprintf("hostc-%d", i) 947 runningOut, err := s.d.Cmd("inspect", "--format='{{.State.Running}}'", cName) 948 c.Assert(err, checker.IsNil) 949 c.Assert(strings.TrimSpace(runningOut), checker.Equals, "true") 950 } 951 } 952 953 func (s *DockerNetworkSuite) TestDockerNetworkConnectToHostFromOtherNetwork(c *check.C) { 954 dockerCmd(c, "run", "-d", "--name", "container1", "busybox", "top") 955 c.Assert(waitRun("container1"), check.IsNil) 956 dockerCmd(c, "network", "disconnect", "bridge", "container1") 957 out, _, err := dockerCmdWithError("network", "connect", "host", "container1") 958 c.Assert(err, checker.NotNil, check.Commentf(out)) 959 c.Assert(out, checker.Contains, runconfig.ErrConflictHostNetwork.Error()) 960 } 961 962 func (s *DockerNetworkSuite) TestDockerNetworkDisconnectFromHost(c *check.C) { 963 dockerCmd(c, "run", "-d", "--name", "container1", "--net=host", "busybox", "top") 964 c.Assert(waitRun("container1"), check.IsNil) 965 out, _, err := dockerCmdWithError("network", "disconnect", "host", "container1") 966 c.Assert(err, checker.NotNil, check.Commentf("Should err out disconnect from host")) 967 c.Assert(out, checker.Contains, runconfig.ErrConflictHostNetwork.Error()) 968 } 969 970 func (s *DockerNetworkSuite) TestDockerNetworkConnectWithPortMapping(c *check.C) { 971 dockerCmd(c, "network", "create", "test1") 972 dockerCmd(c, "run", "-d", "--name", "c1", "-p", "5000:5000", "busybox", "top") 973 c.Assert(waitRun("c1"), check.IsNil) 974 dockerCmd(c, "network", "connect", "test1", "c1") 975 } 976 977 func (s *DockerNetworkSuite) TestDockerNetworkConnectWithMac(c *check.C) { 978 macAddress := "02:42:ac:11:00:02" 979 dockerCmd(c, "network", "create", "mynetwork") 980 dockerCmd(c, "run", "--name=test", "-d", "--mac-address", macAddress, "busybox", "top") 981 c.Assert(waitRun("test"), check.IsNil) 982 mac1, err := inspectField("test", "NetworkSettings.Networks.bridge.MacAddress") 983 c.Assert(err, checker.IsNil) 984 c.Assert(strings.TrimSpace(mac1), checker.Equals, macAddress) 985 dockerCmd(c, "network", "connect", "mynetwork", "test") 986 mac2, err := inspectField("test", "NetworkSettings.Networks.mynetwork.MacAddress") 987 c.Assert(err, checker.IsNil) 988 c.Assert(strings.TrimSpace(mac2), checker.Not(checker.Equals), strings.TrimSpace(mac1)) 989 } 990 991 func (s *DockerNetworkSuite) TestDockerNetworkInspectCreatedContainer(c *check.C) { 992 dockerCmd(c, "create", "--name", "test", "busybox") 993 networks, err := inspectField("test", "NetworkSettings.Networks") 994 c.Assert(err, checker.IsNil) 995 c.Assert(networks, checker.Contains, "bridge", check.Commentf("Should return 'bridge' network")) 996 } 997 998 func (s *DockerNetworkSuite) TestDockerNetworkRestartWithMultipleNetworks(c *check.C) { 999 dockerCmd(c, "network", "create", "test") 1000 dockerCmd(c, "run", "--name=foo", "-d", "busybox", "top") 1001 c.Assert(waitRun("foo"), checker.IsNil) 1002 dockerCmd(c, "network", "connect", "test", "foo") 1003 dockerCmd(c, "restart", "foo") 1004 networks, err := inspectField("foo", "NetworkSettings.Networks") 1005 c.Assert(err, checker.IsNil) 1006 c.Assert(networks, checker.Contains, "bridge", check.Commentf("Should contain 'bridge' network")) 1007 c.Assert(networks, checker.Contains, "test", check.Commentf("Should contain 'test' network")) 1008 } 1009 1010 func (s *DockerNetworkSuite) TestDockerNetworkConnectDisconnectToStoppedContainer(c *check.C) { 1011 dockerCmd(c, "network", "create", "test") 1012 dockerCmd(c, "create", "--name=foo", "busybox", "top") 1013 dockerCmd(c, "network", "connect", "test", "foo") 1014 networks, err := inspectField("foo", "NetworkSettings.Networks") 1015 c.Assert(err, checker.IsNil) 1016 c.Assert(networks, checker.Contains, "test", check.Commentf("Should contain 'test' network")) 1017 1018 // Restart docker daemon to test the config has persisted to disk 1019 s.d.Restart() 1020 networks, err = inspectField("foo", "NetworkSettings.Networks") 1021 c.Assert(err, checker.IsNil) 1022 c.Assert(networks, checker.Contains, "test", check.Commentf("Should contain 'test' network")) 1023 1024 // start the container and test if we can ping it from another container in the same network 1025 dockerCmd(c, "start", "foo") 1026 c.Assert(waitRun("foo"), checker.IsNil) 1027 ip, err := inspectField("foo", "NetworkSettings.Networks.test.IPAddress") 1028 ip = strings.TrimSpace(ip) 1029 dockerCmd(c, "run", "--net=test", "busybox", "sh", "-c", fmt.Sprintf("ping -c 1 %s", ip)) 1030 1031 dockerCmd(c, "stop", "foo") 1032 1033 // Test disconnect 1034 dockerCmd(c, "network", "disconnect", "test", "foo") 1035 networks, err = inspectField("foo", "NetworkSettings.Networks") 1036 c.Assert(err, checker.IsNil) 1037 c.Assert(networks, checker.Not(checker.Contains), "test", check.Commentf("Should not contain 'test' network")) 1038 1039 // Restart docker daemon to test the config has persisted to disk 1040 s.d.Restart() 1041 networks, err = inspectField("foo", "NetworkSettings.Networks") 1042 c.Assert(err, checker.IsNil) 1043 c.Assert(networks, checker.Not(checker.Contains), "test", check.Commentf("Should not contain 'test' network")) 1044 1045 } 1046 1047 func (s *DockerNetworkSuite) TestDockerNetworkConnectPreferredIP(c *check.C) { 1048 // create two networks 1049 dockerCmd(c, "network", "create", "--subnet=172.28.0.0/16", "--subnet=2001:db8:1234::/64", "n0") 1050 assertNwIsAvailable(c, "n0") 1051 1052 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") 1053 assertNwIsAvailable(c, "n1") 1054 1055 // run a container on first network specifying the ip addresses 1056 dockerCmd(c, "run", "-d", "--name", "c0", "--net=n0", "--ip", "172.28.99.88", "--ip6", "2001:db8:1234::9988", "busybox", "top") 1057 c.Assert(waitRun("c0"), check.IsNil) 1058 verifyIPAddresses(c, "c0", "n0", "172.28.99.88", "2001:db8:1234::9988") 1059 1060 // connect the container to the second network specifying the preferred ip addresses 1061 dockerCmd(c, "network", "connect", "--ip", "172.30.55.44", "--ip6", "2001:db8:abcd::5544", "n1", "c0") 1062 verifyIPAddresses(c, "c0", "n1", "172.30.55.44", "2001:db8:abcd::5544") 1063 1064 // Stop and restart the container 1065 dockerCmd(c, "stop", "c0") 1066 dockerCmd(c, "start", "c0") 1067 1068 // verify preferred addresses are applied 1069 verifyIPAddresses(c, "c0", "n0", "172.28.99.88", "2001:db8:1234::9988") 1070 verifyIPAddresses(c, "c0", "n1", "172.30.55.44", "2001:db8:abcd::5544") 1071 1072 // Still it should fail to connect to the default network with a specified IP (whatever ip) 1073 out, _, err := dockerCmdWithError("network", "connect", "--ip", "172.21.55.44", "bridge", "c0") 1074 c.Assert(err, checker.NotNil, check.Commentf("out: %s", out)) 1075 c.Assert(out, checker.Contains, runconfig.ErrUnsupportedNetworkAndIP.Error()) 1076 1077 } 1078 1079 func (s *DockerNetworkSuite) TestDockerNetworkUnsupportedPreferredIP(c *check.C) { 1080 // preferred IP is not supported on predefined networks 1081 for _, mode := range []string{"none", "host", "bridge"} { 1082 checkUnsupportedNetworkAndIP(c, mode) 1083 } 1084 1085 // preferred IP is not supported on networks with no user defined subnets 1086 dockerCmd(c, "network", "create", "n0") 1087 assertNwIsAvailable(c, "n0") 1088 1089 out, _, err := dockerCmdWithError("run", "-d", "--ip", "172.28.99.88", "--net", "n0", "busybox", "top") 1090 c.Assert(err, checker.NotNil, check.Commentf("out: %s", out)) 1091 c.Assert(out, checker.Contains, runconfig.ErrUnsupportedNetworkNoSubnetAndIP.Error()) 1092 1093 out, _, err = dockerCmdWithError("run", "-d", "--ip6", "2001:db8:1234::9988", "--net", "n0", "busybox", "top") 1094 c.Assert(err, checker.NotNil, check.Commentf("out: %s", out)) 1095 c.Assert(out, checker.Contains, runconfig.ErrUnsupportedNetworkNoSubnetAndIP.Error()) 1096 1097 dockerCmd(c, "network", "rm", "n0") 1098 assertNwNotAvailable(c, "n0") 1099 } 1100 1101 func checkUnsupportedNetworkAndIP(c *check.C, nwMode string) { 1102 out, _, err := dockerCmdWithError("run", "-d", "--net", nwMode, "--ip", "172.28.99.88", "--ip6", "2001:db8:1234::9988", "busybox", "top") 1103 c.Assert(err, checker.NotNil, check.Commentf("out: %s", out)) 1104 c.Assert(out, checker.Contains, runconfig.ErrUnsupportedNetworkAndIP.Error()) 1105 } 1106 1107 func verifyIPAddresses(c *check.C, cName, nwname, ipv4, ipv6 string) { 1108 out, _ := dockerCmd(c, "inspect", fmt.Sprintf("--format='{{ .NetworkSettings.Networks.%s.IPAddress }}'", nwname), cName) 1109 c.Assert(strings.TrimSpace(out), check.Equals, ipv4) 1110 1111 out, _ = dockerCmd(c, "inspect", fmt.Sprintf("--format='{{ .NetworkSettings.Networks.%s.GlobalIPv6Address }}'", nwname), cName) 1112 c.Assert(strings.TrimSpace(out), check.Equals, ipv6) 1113 } 1114 1115 func (s *DockerSuite) TestUserDefinedNetworkConnectDisconnectLink(c *check.C) { 1116 testRequires(c, DaemonIsLinux, NotUserNamespace) 1117 dockerCmd(c, "network", "create", "-d", "bridge", "foo1") 1118 dockerCmd(c, "network", "create", "-d", "bridge", "foo2") 1119 1120 dockerCmd(c, "run", "-d", "--net=foo1", "--name=first", "busybox", "top") 1121 c.Assert(waitRun("first"), check.IsNil) 1122 1123 // run a container in user-defined network udlinkNet with a link for an existing container 1124 // and a link for a container that doesnt exist 1125 dockerCmd(c, "run", "-d", "--net=foo1", "--name=second", "--link=first:FirstInFoo1", 1126 "--link=third:bar", "busybox", "top") 1127 c.Assert(waitRun("second"), check.IsNil) 1128 1129 // ping to first and its alias FirstInFoo1 must succeed 1130 _, _, err := dockerCmdWithError("exec", "second", "ping", "-c", "1", "first") 1131 c.Assert(err, check.IsNil) 1132 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "FirstInFoo1") 1133 c.Assert(err, check.IsNil) 1134 1135 // connect first container to foo2 network 1136 dockerCmd(c, "network", "connect", "foo2", "first") 1137 // connect second container to foo2 network with a different alias for first container 1138 dockerCmd(c, "network", "connect", "--link=first:FirstInFoo2", "foo2", "second") 1139 1140 // ping the new alias in network foo2 1141 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "FirstInFoo2") 1142 c.Assert(err, check.IsNil) 1143 1144 // disconnect first container from foo1 network 1145 dockerCmd(c, "network", "disconnect", "foo1", "first") 1146 1147 // link in foo1 network must fail 1148 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "FirstInFoo1") 1149 c.Assert(err, check.NotNil) 1150 1151 // link in foo2 network must succeed 1152 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "FirstInFoo2") 1153 c.Assert(err, check.IsNil) 1154 } 1155 1156 // #19100 This is a deprecated feature test, it should be remove in Docker 1.12 1157 func (s *DockerNetworkSuite) TestDockerNetworkStartAPIWithHostconfig(c *check.C) { 1158 netName := "test" 1159 conName := "foo" 1160 dockerCmd(c, "network", "create", netName) 1161 dockerCmd(c, "create", "--name", conName, "busybox", "top") 1162 1163 config := map[string]interface{}{ 1164 "HostConfig": map[string]interface{}{ 1165 "NetworkMode": netName, 1166 }, 1167 } 1168 _, _, err := sockRequest("POST", "/containers/"+conName+"/start", config) 1169 c.Assert(err, checker.IsNil) 1170 c.Assert(waitRun(conName), checker.IsNil) 1171 networks, err := inspectField(conName, "NetworkSettings.Networks") 1172 c.Assert(err, checker.IsNil) 1173 c.Assert(networks, checker.Contains, netName, check.Commentf(fmt.Sprintf("Should contain '%s' network", netName))) 1174 c.Assert(networks, checker.Not(checker.Contains), "bridge", check.Commentf("Should not contain 'bridge' network")) 1175 } 1176 1177 func (s *DockerNetworkSuite) TestDockerNetworkDisconnectDefault(c *check.C) { 1178 netWorkName1 := "test1" 1179 netWorkName2 := "test2" 1180 containerName := "foo" 1181 1182 dockerCmd(c, "network", "create", netWorkName1) 1183 dockerCmd(c, "network", "create", netWorkName2) 1184 dockerCmd(c, "create", "--name", containerName, "busybox", "top") 1185 dockerCmd(c, "network", "connect", netWorkName1, containerName) 1186 dockerCmd(c, "network", "connect", netWorkName2, containerName) 1187 dockerCmd(c, "network", "disconnect", "bridge", containerName) 1188 1189 dockerCmd(c, "start", containerName) 1190 c.Assert(waitRun(containerName), checker.IsNil) 1191 networks, err := inspectField(containerName, "NetworkSettings.Networks") 1192 c.Assert(err, checker.IsNil) 1193 c.Assert(networks, checker.Contains, netWorkName1, check.Commentf(fmt.Sprintf("Should contain '%s' network", netWorkName1))) 1194 c.Assert(networks, checker.Contains, netWorkName2, check.Commentf(fmt.Sprintf("Should contain '%s' network", netWorkName2))) 1195 c.Assert(networks, checker.Not(checker.Contains), "bridge", check.Commentf("Should not contain 'bridge' network")) 1196 } 1197 1198 func (s *DockerSuite) TestUserDefinedNetworkConnectDisconnectAlias(c *check.C) { 1199 testRequires(c, DaemonIsLinux, NotUserNamespace) 1200 dockerCmd(c, "network", "create", "-d", "bridge", "net1") 1201 dockerCmd(c, "network", "create", "-d", "bridge", "net2") 1202 1203 dockerCmd(c, "run", "-d", "--net=net1", "--name=first", "--net-alias=foo", "busybox", "top") 1204 c.Assert(waitRun("first"), check.IsNil) 1205 1206 dockerCmd(c, "run", "-d", "--net=net1", "--name=second", "busybox", "top") 1207 c.Assert(waitRun("second"), check.IsNil) 1208 1209 // ping first container and its alias 1210 _, _, err := dockerCmdWithError("exec", "second", "ping", "-c", "1", "first") 1211 c.Assert(err, check.IsNil) 1212 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "foo") 1213 c.Assert(err, check.IsNil) 1214 1215 // connect first container to net2 network 1216 dockerCmd(c, "network", "connect", "--alias=bar", "net2", "first") 1217 // connect second container to foo2 network with a different alias for first container 1218 dockerCmd(c, "network", "connect", "net2", "second") 1219 1220 // ping the new alias in network foo2 1221 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "bar") 1222 c.Assert(err, check.IsNil) 1223 1224 // disconnect first container from net1 network 1225 dockerCmd(c, "network", "disconnect", "net1", "first") 1226 1227 // ping to net1 scoped alias "foo" must fail 1228 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "foo") 1229 c.Assert(err, check.NotNil) 1230 1231 // ping to net2 scoped alias "bar" must still succeed 1232 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "bar") 1233 c.Assert(err, check.IsNil) 1234 }