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