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