github.com/jwhonce/docker@v0.6.7-0.20190327063223-da823cf3a5a3/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/vishvananda/netlink" 31 "golang.org/x/sys/unix" 32 "gotest.tools/icmd" 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 var 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 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 var 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 var 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 var 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 var 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 var 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, testEnv.IsLocalDaemon) 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.170.0.0/16", "--subnet=192.171.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.172.0.0/16", "--subnet=192.173.0.0/16", 620 "--gateway=192.172.0.100", "--gateway=192.173.0.100", 621 "--ip-range=192.172.1.0/24", 622 "--aux-address", "a=192.172.1.5", "--aux-address", "b=192.172.1.6", 623 "--aux-address", "c=192.173.1.5", "--aux-address", "d=192.173.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, testEnv.IsLocalDaemon) 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, testEnv.IsLocalDaemon) 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, testEnv.IsLocalDaemon) 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, testEnv.IsLocalDaemon) 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("%s", 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("%s", 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 // verify first container etc/hosts file has not changed 884 hosts1post := readContainerFileWithExec(c, cid1, hostsFile) 885 c.Assert(string(hosts1), checker.Equals, string(hosts1post), 886 check.Commentf("Unexpected %s change on anonymous container creation", hostsFile)) 887 888 // Connect the 2nd container to a new network and verify the 889 // first container /etc/hosts file still hasn't changed. 890 dockerCmd(c, "network", "create", "-d", "bridge", cstmBridgeNw1) 891 assertNwIsAvailable(c, cstmBridgeNw1) 892 893 dockerCmd(c, "network", "connect", cstmBridgeNw1, cid2) 894 895 hosts2 := readContainerFileWithExec(c, cid2, hostsFile) 896 hosts1post = readContainerFileWithExec(c, cid1, hostsFile) 897 c.Assert(string(hosts1), checker.Equals, string(hosts1post), 898 check.Commentf("Unexpected %s change on container connect", hostsFile)) 899 900 // start a named container 901 cName := "AnyName" 902 out, _ = dockerCmd(c, "run", "-d", "--net", cstmBridgeNw, "--name", cName, "busybox", "top") 903 cid3 := strings.TrimSpace(out) 904 905 // verify that container 1 and 2 can ping the named container 906 dockerCmd(c, "exec", cid1, "ping", "-c", "1", cName) 907 dockerCmd(c, "exec", cid2, "ping", "-c", "1", cName) 908 909 // Stop named container and verify first two containers' etc/hosts file hasn't changed 910 dockerCmd(c, "stop", cid3) 911 hosts1post = readContainerFileWithExec(c, cid1, hostsFile) 912 c.Assert(string(hosts1), checker.Equals, string(hosts1post), 913 check.Commentf("Unexpected %s change on name container creation", hostsFile)) 914 915 hosts2post := readContainerFileWithExec(c, cid2, hostsFile) 916 c.Assert(string(hosts2), checker.Equals, string(hosts2post), 917 check.Commentf("Unexpected %s change on name container creation", hostsFile)) 918 919 // verify that container 1 and 2 can't ping the named container now 920 _, _, err := dockerCmdWithError("exec", cid1, "ping", "-c", "1", cName) 921 c.Assert(err, check.NotNil) 922 _, _, err = dockerCmdWithError("exec", cid2, "ping", "-c", "1", cName) 923 c.Assert(err, check.NotNil) 924 } 925 926 func (s *DockerNetworkSuite) TestDockerNetworkLinkOnDefaultNetworkOnly(c *check.C) { 927 // Legacy Link feature must work only on default network, and not across networks 928 cnt1 := "container1" 929 cnt2 := "container2" 930 network := "anotherbridge" 931 932 // Run first container on default network 933 dockerCmd(c, "run", "-d", "--name", cnt1, "busybox", "top") 934 935 // Create another network and run the second container on it 936 dockerCmd(c, "network", "create", network) 937 assertNwIsAvailable(c, network) 938 dockerCmd(c, "run", "-d", "--net", network, "--name", cnt2, "busybox", "top") 939 940 // Try launching a container on default network, linking to the first container. Must succeed 941 dockerCmd(c, "run", "-d", "--link", fmt.Sprintf("%s:%s", cnt1, cnt1), "busybox", "top") 942 943 // Try launching a container on default network, linking to the second container. Must fail 944 _, _, err := dockerCmdWithError("run", "-d", "--link", fmt.Sprintf("%s:%s", cnt2, cnt2), "busybox", "top") 945 c.Assert(err, checker.NotNil) 946 947 // Connect second container to default network. Now a container on default network can link to it 948 dockerCmd(c, "network", "connect", "bridge", cnt2) 949 dockerCmd(c, "run", "-d", "--link", fmt.Sprintf("%s:%s", cnt2, cnt2), "busybox", "top") 950 } 951 952 func (s *DockerNetworkSuite) TestDockerNetworkOverlayPortMapping(c *check.C) { 953 testRequires(c, testEnv.IsLocalDaemon) 954 // Verify exposed ports are present in ps output when running a container on 955 // a network managed by a driver which does not provide the default gateway 956 // for the container 957 nwn := "ov" 958 ctn := "bb" 959 port1 := 80 960 port2 := 443 961 expose1 := fmt.Sprintf("--expose=%d", port1) 962 expose2 := fmt.Sprintf("--expose=%d", port2) 963 964 dockerCmd(c, "network", "create", "-d", dummyNetworkDriver, nwn) 965 assertNwIsAvailable(c, nwn) 966 967 dockerCmd(c, "run", "-d", "--net", nwn, "--name", ctn, expose1, expose2, "busybox", "top") 968 969 // Check docker ps o/p for last created container reports the unpublished ports 970 unpPort1 := fmt.Sprintf("%d/tcp", port1) 971 unpPort2 := fmt.Sprintf("%d/tcp", port2) 972 out, _ := dockerCmd(c, "ps", "-n=1") 973 // Missing unpublished ports in docker ps output 974 c.Assert(out, checker.Contains, unpPort1) 975 // Missing unpublished ports in docker ps output 976 c.Assert(out, checker.Contains, unpPort2) 977 } 978 979 func (s *DockerNetworkSuite) TestDockerNetworkDriverUngracefulRestart(c *check.C) { 980 testRequires(c, DaemonIsLinux, NotUserNamespace, testEnv.IsLocalDaemon) 981 dnd := "dnd" 982 did := "did" 983 984 mux := http.NewServeMux() 985 server := httptest.NewServer(mux) 986 setupRemoteNetworkDrivers(c, mux, server.URL, dnd, did) 987 988 s.d.StartWithBusybox(c) 989 _, err := s.d.Cmd("network", "create", "-d", dnd, "--subnet", "1.1.1.0/24", "net1") 990 c.Assert(err, checker.IsNil) 991 992 _, err = s.d.Cmd("run", "-itd", "--net", "net1", "--name", "foo", "--ip", "1.1.1.10", "busybox", "sh") 993 c.Assert(err, checker.IsNil) 994 995 // Kill daemon and restart 996 c.Assert(s.d.Kill(), checker.IsNil) 997 998 server.Close() 999 1000 startTime := time.Now().Unix() 1001 s.d.Restart(c) 1002 lapse := time.Now().Unix() - startTime 1003 if lapse > 60 { 1004 // In normal scenarios, daemon restart takes ~1 second. 1005 // Plugin retry mechanism can delay the daemon start. systemd may not like it. 1006 // Avoid accessing plugins during daemon bootup 1007 c.Logf("daemon restart took too long : %d seconds", lapse) 1008 } 1009 1010 // Restart the custom dummy plugin 1011 mux = http.NewServeMux() 1012 server = httptest.NewServer(mux) 1013 setupRemoteNetworkDrivers(c, mux, server.URL, dnd, did) 1014 1015 // trying to reuse the same ip must succeed 1016 _, err = s.d.Cmd("run", "-itd", "--net", "net1", "--name", "bar", "--ip", "1.1.1.10", "busybox", "sh") 1017 c.Assert(err, checker.IsNil) 1018 } 1019 1020 func (s *DockerNetworkSuite) TestDockerNetworkMacInspect(c *check.C) { 1021 testRequires(c, testEnv.IsLocalDaemon) 1022 // Verify endpoint MAC address is correctly populated in container's network settings 1023 nwn := "ov" 1024 ctn := "bb" 1025 1026 dockerCmd(c, "network", "create", "-d", dummyNetworkDriver, nwn) 1027 assertNwIsAvailable(c, nwn) 1028 1029 dockerCmd(c, "run", "-d", "--net", nwn, "--name", ctn, "busybox", "top") 1030 1031 mac := inspectField(c, ctn, "NetworkSettings.Networks."+nwn+".MacAddress") 1032 c.Assert(mac, checker.Equals, "a0:b1:c2:d3:e4:f5") 1033 } 1034 1035 func (s *DockerSuite) TestInspectAPIMultipleNetworks(c *check.C) { 1036 dockerCmd(c, "network", "create", "mybridge1") 1037 dockerCmd(c, "network", "create", "mybridge2") 1038 out, _ := dockerCmd(c, "run", "-d", "busybox", "top") 1039 id := strings.TrimSpace(out) 1040 c.Assert(waitRun(id), check.IsNil) 1041 1042 dockerCmd(c, "network", "connect", "mybridge1", id) 1043 dockerCmd(c, "network", "connect", "mybridge2", id) 1044 1045 body := getInspectBody(c, "v1.20", id) 1046 var inspect120 v1p20.ContainerJSON 1047 err := json.Unmarshal(body, &inspect120) 1048 c.Assert(err, checker.IsNil) 1049 1050 versionedIP := inspect120.NetworkSettings.IPAddress 1051 1052 body = getInspectBody(c, "v1.21", id) 1053 var inspect121 types.ContainerJSON 1054 err = json.Unmarshal(body, &inspect121) 1055 c.Assert(err, checker.IsNil) 1056 c.Assert(inspect121.NetworkSettings.Networks, checker.HasLen, 3) 1057 1058 bridge := inspect121.NetworkSettings.Networks["bridge"] 1059 c.Assert(bridge.IPAddress, checker.Equals, versionedIP) 1060 c.Assert(bridge.IPAddress, checker.Equals, inspect121.NetworkSettings.IPAddress) 1061 } 1062 1063 func connectContainerToNetworks(c *check.C, d *daemon.Daemon, cName string, nws []string) { 1064 // Run a container on the default network 1065 out, err := d.Cmd("run", "-d", "--name", cName, "busybox", "top") 1066 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 1067 1068 // Attach the container to other networks 1069 for _, nw := range nws { 1070 out, err = d.Cmd("network", "create", nw) 1071 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 1072 out, err = d.Cmd("network", "connect", nw, cName) 1073 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 1074 } 1075 } 1076 1077 func verifyContainerIsConnectedToNetworks(c *check.C, d *daemon.Daemon, cName string, nws []string) { 1078 // Verify container is connected to all the networks 1079 for _, nw := range nws { 1080 out, err := d.Cmd("inspect", "-f", fmt.Sprintf("{{.NetworkSettings.Networks.%s}}", nw), cName) 1081 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 1082 c.Assert(out, checker.Not(checker.Equals), "<no value>\n") 1083 } 1084 } 1085 1086 func (s *DockerNetworkSuite) TestDockerNetworkMultipleNetworksGracefulDaemonRestart(c *check.C) { 1087 testRequires(c, testEnv.IsLocalDaemon) 1088 cName := "bb" 1089 nwList := []string{"nw1", "nw2", "nw3"} 1090 1091 s.d.StartWithBusybox(c) 1092 1093 connectContainerToNetworks(c, s.d, cName, nwList) 1094 verifyContainerIsConnectedToNetworks(c, s.d, cName, nwList) 1095 1096 // Reload daemon 1097 s.d.Restart(c) 1098 1099 _, err := s.d.Cmd("start", cName) 1100 c.Assert(err, checker.IsNil) 1101 1102 verifyContainerIsConnectedToNetworks(c, s.d, cName, nwList) 1103 } 1104 1105 func (s *DockerNetworkSuite) TestDockerNetworkMultipleNetworksUngracefulDaemonRestart(c *check.C) { 1106 testRequires(c, testEnv.IsLocalDaemon) 1107 cName := "cc" 1108 nwList := []string{"nw1", "nw2", "nw3"} 1109 1110 s.d.StartWithBusybox(c) 1111 1112 connectContainerToNetworks(c, s.d, cName, nwList) 1113 verifyContainerIsConnectedToNetworks(c, s.d, cName, nwList) 1114 1115 // Kill daemon and restart 1116 c.Assert(s.d.Kill(), checker.IsNil) 1117 s.d.Restart(c) 1118 1119 // Restart container 1120 _, err := s.d.Cmd("start", cName) 1121 c.Assert(err, checker.IsNil) 1122 1123 verifyContainerIsConnectedToNetworks(c, s.d, cName, nwList) 1124 } 1125 1126 func (s *DockerNetworkSuite) TestDockerNetworkRunNetByID(c *check.C) { 1127 out, _ := dockerCmd(c, "network", "create", "one") 1128 containerOut, _, err := dockerCmdWithError("run", "-d", "--net", strings.TrimSpace(out), "busybox", "top") 1129 c.Assert(err, checker.IsNil, check.Commentf(containerOut)) 1130 } 1131 1132 func (s *DockerNetworkSuite) TestDockerNetworkHostModeUngracefulDaemonRestart(c *check.C) { 1133 testRequires(c, DaemonIsLinux, NotUserNamespace, testEnv.IsLocalDaemon) 1134 s.d.StartWithBusybox(c) 1135 1136 // Run a few containers on host network 1137 for i := 0; i < 10; i++ { 1138 cName := fmt.Sprintf("hostc-%d", i) 1139 out, err := s.d.Cmd("run", "-d", "--name", cName, "--net=host", "--restart=always", "busybox", "top") 1140 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 1141 1142 // verify container has finished starting before killing daemon 1143 err = s.d.WaitRun(cName) 1144 c.Assert(err, checker.IsNil) 1145 } 1146 1147 // Kill daemon ungracefully and restart 1148 c.Assert(s.d.Kill(), checker.IsNil) 1149 s.d.Restart(c) 1150 1151 // make sure all the containers are up and running 1152 for i := 0; i < 10; i++ { 1153 err := s.d.WaitRun(fmt.Sprintf("hostc-%d", i)) 1154 c.Assert(err, checker.IsNil) 1155 } 1156 } 1157 1158 func (s *DockerNetworkSuite) TestDockerNetworkConnectToHostFromOtherNetwork(c *check.C) { 1159 dockerCmd(c, "run", "-d", "--name", "container1", "busybox", "top") 1160 c.Assert(waitRun("container1"), check.IsNil) 1161 dockerCmd(c, "network", "disconnect", "bridge", "container1") 1162 out, _, err := dockerCmdWithError("network", "connect", "host", "container1") 1163 c.Assert(err, checker.NotNil, check.Commentf("%s", out)) 1164 c.Assert(out, checker.Contains, runconfig.ErrConflictHostNetwork.Error()) 1165 } 1166 1167 func (s *DockerNetworkSuite) TestDockerNetworkDisconnectFromHost(c *check.C) { 1168 dockerCmd(c, "run", "-d", "--name", "container1", "--net=host", "busybox", "top") 1169 c.Assert(waitRun("container1"), check.IsNil) 1170 out, _, err := dockerCmdWithError("network", "disconnect", "host", "container1") 1171 c.Assert(err, checker.NotNil, check.Commentf("Should err out disconnect from host")) 1172 c.Assert(out, checker.Contains, runconfig.ErrConflictHostNetwork.Error()) 1173 } 1174 1175 func (s *DockerNetworkSuite) TestDockerNetworkConnectWithPortMapping(c *check.C) { 1176 testRequires(c, NotArm) 1177 dockerCmd(c, "network", "create", "test1") 1178 dockerCmd(c, "run", "-d", "--name", "c1", "-p", "5000:5000", "busybox", "top") 1179 c.Assert(waitRun("c1"), check.IsNil) 1180 dockerCmd(c, "network", "connect", "test1", "c1") 1181 } 1182 1183 func verifyPortMap(c *check.C, container, port, originalMapping string, mustBeEqual bool) { 1184 chk := checker.Equals 1185 if !mustBeEqual { 1186 chk = checker.Not(checker.Equals) 1187 } 1188 currentMapping, _ := dockerCmd(c, "port", container, port) 1189 c.Assert(currentMapping, chk, originalMapping) 1190 } 1191 1192 func (s *DockerNetworkSuite) TestDockerNetworkConnectDisconnectWithPortMapping(c *check.C) { 1193 // Connect and disconnect a container with explicit and non-explicit 1194 // host port mapping to/from networks which do cause and do not cause 1195 // the container default gateway to change, and verify docker port cmd 1196 // returns congruent information 1197 testRequires(c, NotArm) 1198 cnt := "c1" 1199 dockerCmd(c, "network", "create", "aaa") 1200 dockerCmd(c, "network", "create", "ccc") 1201 1202 dockerCmd(c, "run", "-d", "--name", cnt, "-p", "9000:90", "-p", "70", "busybox", "top") 1203 c.Assert(waitRun(cnt), check.IsNil) 1204 curPortMap, _ := dockerCmd(c, "port", cnt, "70") 1205 curExplPortMap, _ := dockerCmd(c, "port", cnt, "90") 1206 1207 // Connect to a network which causes the container's default gw switch 1208 dockerCmd(c, "network", "connect", "aaa", cnt) 1209 verifyPortMap(c, cnt, "70", curPortMap, false) 1210 verifyPortMap(c, cnt, "90", curExplPortMap, true) 1211 1212 // Read current mapping 1213 curPortMap, _ = dockerCmd(c, "port", cnt, "70") 1214 1215 // Disconnect from a network which causes the container's default gw switch 1216 dockerCmd(c, "network", "disconnect", "aaa", cnt) 1217 verifyPortMap(c, cnt, "70", curPortMap, false) 1218 verifyPortMap(c, cnt, "90", curExplPortMap, true) 1219 1220 // Read current mapping 1221 curPortMap, _ = dockerCmd(c, "port", cnt, "70") 1222 1223 // Connect to a network which does not cause the container's default gw switch 1224 dockerCmd(c, "network", "connect", "ccc", cnt) 1225 verifyPortMap(c, cnt, "70", curPortMap, true) 1226 verifyPortMap(c, cnt, "90", curExplPortMap, true) 1227 } 1228 1229 func (s *DockerNetworkSuite) TestDockerNetworkConnectWithMac(c *check.C) { 1230 macAddress := "02:42:ac:11:00:02" 1231 dockerCmd(c, "network", "create", "mynetwork") 1232 dockerCmd(c, "run", "--name=test", "-d", "--mac-address", macAddress, "busybox", "top") 1233 c.Assert(waitRun("test"), check.IsNil) 1234 mac1 := inspectField(c, "test", "NetworkSettings.Networks.bridge.MacAddress") 1235 c.Assert(strings.TrimSpace(mac1), checker.Equals, macAddress) 1236 dockerCmd(c, "network", "connect", "mynetwork", "test") 1237 mac2 := inspectField(c, "test", "NetworkSettings.Networks.mynetwork.MacAddress") 1238 c.Assert(strings.TrimSpace(mac2), checker.Not(checker.Equals), strings.TrimSpace(mac1)) 1239 } 1240 1241 func (s *DockerNetworkSuite) TestDockerNetworkInspectCreatedContainer(c *check.C) { 1242 dockerCmd(c, "create", "--name", "test", "busybox") 1243 networks := inspectField(c, "test", "NetworkSettings.Networks") 1244 c.Assert(networks, checker.Contains, "bridge", check.Commentf("Should return 'bridge' network")) 1245 } 1246 1247 func (s *DockerNetworkSuite) TestDockerNetworkRestartWithMultipleNetworks(c *check.C) { 1248 dockerCmd(c, "network", "create", "test") 1249 dockerCmd(c, "run", "--name=foo", "-d", "busybox", "top") 1250 c.Assert(waitRun("foo"), checker.IsNil) 1251 dockerCmd(c, "network", "connect", "test", "foo") 1252 dockerCmd(c, "restart", "foo") 1253 networks := inspectField(c, "foo", "NetworkSettings.Networks") 1254 c.Assert(networks, checker.Contains, "bridge", check.Commentf("Should contain 'bridge' network")) 1255 c.Assert(networks, checker.Contains, "test", check.Commentf("Should contain 'test' network")) 1256 } 1257 1258 func (s *DockerNetworkSuite) TestDockerNetworkConnectDisconnectToStoppedContainer(c *check.C) { 1259 testRequires(c, testEnv.IsLocalDaemon) 1260 dockerCmd(c, "network", "create", "test") 1261 dockerCmd(c, "create", "--name=foo", "busybox", "top") 1262 dockerCmd(c, "network", "connect", "test", "foo") 1263 networks := inspectField(c, "foo", "NetworkSettings.Networks") 1264 c.Assert(networks, checker.Contains, "test", check.Commentf("Should contain 'test' network")) 1265 1266 // Restart docker daemon to test the config has persisted to disk 1267 s.d.Restart(c) 1268 networks = inspectField(c, "foo", "NetworkSettings.Networks") 1269 c.Assert(networks, checker.Contains, "test", check.Commentf("Should contain 'test' network")) 1270 1271 // start the container and test if we can ping it from another container in the same network 1272 dockerCmd(c, "start", "foo") 1273 c.Assert(waitRun("foo"), checker.IsNil) 1274 ip := inspectField(c, "foo", "NetworkSettings.Networks.test.IPAddress") 1275 ip = strings.TrimSpace(ip) 1276 dockerCmd(c, "run", "--net=test", "busybox", "sh", "-c", fmt.Sprintf("ping -c 1 %s", ip)) 1277 1278 dockerCmd(c, "stop", "foo") 1279 1280 // Test disconnect 1281 dockerCmd(c, "network", "disconnect", "test", "foo") 1282 networks = inspectField(c, "foo", "NetworkSettings.Networks") 1283 c.Assert(networks, checker.Not(checker.Contains), "test", check.Commentf("Should not contain 'test' network")) 1284 1285 // Restart docker daemon to test the config has persisted to disk 1286 s.d.Restart(c) 1287 networks = inspectField(c, "foo", "NetworkSettings.Networks") 1288 c.Assert(networks, checker.Not(checker.Contains), "test", check.Commentf("Should not contain 'test' network")) 1289 1290 } 1291 1292 func (s *DockerNetworkSuite) TestDockerNetworkDisconnectContainerNonexistingNetwork(c *check.C) { 1293 dockerCmd(c, "network", "create", "test") 1294 dockerCmd(c, "run", "--net=test", "-d", "--name=foo", "busybox", "top") 1295 networks := inspectField(c, "foo", "NetworkSettings.Networks") 1296 c.Assert(networks, checker.Contains, "test", check.Commentf("Should contain 'test' network")) 1297 1298 // Stop container and remove network 1299 dockerCmd(c, "stop", "foo") 1300 dockerCmd(c, "network", "rm", "test") 1301 1302 // Test disconnecting stopped container from nonexisting network 1303 dockerCmd(c, "network", "disconnect", "-f", "test", "foo") 1304 networks = inspectField(c, "foo", "NetworkSettings.Networks") 1305 c.Assert(networks, checker.Not(checker.Contains), "test", check.Commentf("Should not contain 'test' network")) 1306 } 1307 1308 func (s *DockerNetworkSuite) TestDockerNetworkConnectPreferredIP(c *check.C) { 1309 // create two networks 1310 dockerCmd(c, "network", "create", "--ipv6", "--subnet=172.28.0.0/16", "--subnet=2001:db8:1234::/64", "n0") 1311 assertNwIsAvailable(c, "n0") 1312 1313 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") 1314 assertNwIsAvailable(c, "n1") 1315 1316 // run a container on first network specifying the ip addresses 1317 dockerCmd(c, "run", "-d", "--name", "c0", "--net=n0", "--ip", "172.28.99.88", "--ip6", "2001:db8:1234::9988", "busybox", "top") 1318 c.Assert(waitRun("c0"), check.IsNil) 1319 verifyIPAddressConfig(c, "c0", "n0", "172.28.99.88", "2001:db8:1234::9988") 1320 verifyIPAddresses(c, "c0", "n0", "172.28.99.88", "2001:db8:1234::9988") 1321 1322 // connect the container to the second network specifying an ip addresses 1323 dockerCmd(c, "network", "connect", "--ip", "172.30.55.44", "--ip6", "2001:db8:abcd::5544", "n1", "c0") 1324 verifyIPAddressConfig(c, "c0", "n1", "172.30.55.44", "2001:db8:abcd::5544") 1325 verifyIPAddresses(c, "c0", "n1", "172.30.55.44", "2001:db8:abcd::5544") 1326 1327 // Stop and restart the container 1328 dockerCmd(c, "stop", "c0") 1329 dockerCmd(c, "start", "c0") 1330 1331 // verify requested addresses are applied and configs are still there 1332 verifyIPAddressConfig(c, "c0", "n0", "172.28.99.88", "2001:db8:1234::9988") 1333 verifyIPAddresses(c, "c0", "n0", "172.28.99.88", "2001:db8:1234::9988") 1334 verifyIPAddressConfig(c, "c0", "n1", "172.30.55.44", "2001:db8:abcd::5544") 1335 verifyIPAddresses(c, "c0", "n1", "172.30.55.44", "2001:db8:abcd::5544") 1336 1337 // Still it should fail to connect to the default network with a specified IP (whatever ip) 1338 out, _, err := dockerCmdWithError("network", "connect", "--ip", "172.21.55.44", "bridge", "c0") 1339 c.Assert(err, checker.NotNil, check.Commentf("out: %s", out)) 1340 c.Assert(out, checker.Contains, runconfig.ErrUnsupportedNetworkAndIP.Error()) 1341 1342 } 1343 1344 func (s *DockerNetworkSuite) TestDockerNetworkConnectPreferredIPStoppedContainer(c *check.C) { 1345 // create a container 1346 dockerCmd(c, "create", "--name", "c0", "busybox", "top") 1347 1348 // create a network 1349 dockerCmd(c, "network", "create", "--ipv6", "--subnet=172.30.0.0/16", "--subnet=2001:db8:abcd::/64", "n0") 1350 assertNwIsAvailable(c, "n0") 1351 1352 // connect the container to the network specifying an ip addresses 1353 dockerCmd(c, "network", "connect", "--ip", "172.30.55.44", "--ip6", "2001:db8:abcd::5544", "n0", "c0") 1354 verifyIPAddressConfig(c, "c0", "n0", "172.30.55.44", "2001:db8:abcd::5544") 1355 1356 // start the container, verify config has not changed and ip addresses are assigned 1357 dockerCmd(c, "start", "c0") 1358 c.Assert(waitRun("c0"), check.IsNil) 1359 verifyIPAddressConfig(c, "c0", "n0", "172.30.55.44", "2001:db8:abcd::5544") 1360 verifyIPAddresses(c, "c0", "n0", "172.30.55.44", "2001:db8:abcd::5544") 1361 1362 // stop the container and check ip config has not changed 1363 dockerCmd(c, "stop", "c0") 1364 verifyIPAddressConfig(c, "c0", "n0", "172.30.55.44", "2001:db8:abcd::5544") 1365 } 1366 1367 func (s *DockerNetworkSuite) TestDockerNetworkUnsupportedRequiredIP(c *check.C) { 1368 // requested IP is not supported on predefined networks 1369 for _, mode := range []string{"none", "host", "bridge", "default"} { 1370 checkUnsupportedNetworkAndIP(c, mode) 1371 } 1372 1373 // requested IP is not supported on networks with no user defined subnets 1374 dockerCmd(c, "network", "create", "n0") 1375 assertNwIsAvailable(c, "n0") 1376 1377 out, _, err := dockerCmdWithError("run", "-d", "--ip", "172.28.99.88", "--net", "n0", "busybox", "top") 1378 c.Assert(err, checker.NotNil, check.Commentf("out: %s", out)) 1379 c.Assert(out, checker.Contains, runconfig.ErrUnsupportedNetworkNoSubnetAndIP.Error()) 1380 1381 out, _, err = dockerCmdWithError("run", "-d", "--ip6", "2001:db8:1234::9988", "--net", "n0", "busybox", "top") 1382 c.Assert(err, checker.NotNil, check.Commentf("out: %s", out)) 1383 c.Assert(out, checker.Contains, runconfig.ErrUnsupportedNetworkNoSubnetAndIP.Error()) 1384 1385 dockerCmd(c, "network", "rm", "n0") 1386 assertNwNotAvailable(c, "n0") 1387 } 1388 1389 func checkUnsupportedNetworkAndIP(c *check.C, nwMode string) { 1390 out, _, err := dockerCmdWithError("run", "-d", "--net", nwMode, "--ip", "172.28.99.88", "--ip6", "2001:db8:1234::9988", "busybox", "top") 1391 c.Assert(err, checker.NotNil, check.Commentf("out: %s", out)) 1392 c.Assert(out, checker.Contains, runconfig.ErrUnsupportedNetworkAndIP.Error()) 1393 } 1394 1395 func verifyIPAddressConfig(c *check.C, cName, nwname, ipv4, ipv6 string) { 1396 if ipv4 != "" { 1397 out := inspectField(c, cName, fmt.Sprintf("NetworkSettings.Networks.%s.IPAMConfig.IPv4Address", nwname)) 1398 c.Assert(strings.TrimSpace(out), check.Equals, ipv4) 1399 } 1400 1401 if ipv6 != "" { 1402 out := inspectField(c, cName, fmt.Sprintf("NetworkSettings.Networks.%s.IPAMConfig.IPv6Address", nwname)) 1403 c.Assert(strings.TrimSpace(out), check.Equals, ipv6) 1404 } 1405 } 1406 1407 func verifyIPAddresses(c *check.C, cName, nwname, ipv4, ipv6 string) { 1408 out := inspectField(c, cName, fmt.Sprintf("NetworkSettings.Networks.%s.IPAddress", nwname)) 1409 c.Assert(strings.TrimSpace(out), check.Equals, ipv4) 1410 1411 out = inspectField(c, cName, fmt.Sprintf("NetworkSettings.Networks.%s.GlobalIPv6Address", nwname)) 1412 c.Assert(strings.TrimSpace(out), check.Equals, ipv6) 1413 } 1414 1415 func (s *DockerNetworkSuite) TestDockerNetworkConnectLinkLocalIP(c *check.C) { 1416 // create one test network 1417 dockerCmd(c, "network", "create", "--ipv6", "--subnet=2001:db8:1234::/64", "n0") 1418 assertNwIsAvailable(c, "n0") 1419 1420 // run a container with incorrect link-local address 1421 _, _, err := dockerCmdWithError("run", "--link-local-ip", "169.253.5.5", "busybox", "top") 1422 c.Assert(err, check.NotNil) 1423 _, _, err = dockerCmdWithError("run", "--link-local-ip", "2001:db8::89", "busybox", "top") 1424 c.Assert(err, check.NotNil) 1425 1426 // run two containers with link-local ip on the test network 1427 dockerCmd(c, "run", "-d", "--name", "c0", "--net=n0", "--link-local-ip", "169.254.7.7", "--link-local-ip", "fe80::254:77", "busybox", "top") 1428 c.Assert(waitRun("c0"), check.IsNil) 1429 dockerCmd(c, "run", "-d", "--name", "c1", "--net=n0", "--link-local-ip", "169.254.8.8", "--link-local-ip", "fe80::254:88", "busybox", "top") 1430 c.Assert(waitRun("c1"), check.IsNil) 1431 1432 // run a container on the default network and connect it to the test network specifying a link-local address 1433 dockerCmd(c, "run", "-d", "--name", "c2", "busybox", "top") 1434 c.Assert(waitRun("c2"), check.IsNil) 1435 dockerCmd(c, "network", "connect", "--link-local-ip", "169.254.9.9", "n0", "c2") 1436 1437 // verify the three containers can ping each other via the link-local addresses 1438 _, _, err = dockerCmdWithError("exec", "c0", "ping", "-c", "1", "169.254.8.8") 1439 c.Assert(err, check.IsNil) 1440 _, _, err = dockerCmdWithError("exec", "c1", "ping", "-c", "1", "169.254.9.9") 1441 c.Assert(err, check.IsNil) 1442 _, _, err = dockerCmdWithError("exec", "c2", "ping", "-c", "1", "169.254.7.7") 1443 c.Assert(err, check.IsNil) 1444 1445 // Stop and restart the three containers 1446 dockerCmd(c, "stop", "c0") 1447 dockerCmd(c, "stop", "c1") 1448 dockerCmd(c, "stop", "c2") 1449 dockerCmd(c, "start", "c0") 1450 dockerCmd(c, "start", "c1") 1451 dockerCmd(c, "start", "c2") 1452 1453 // verify the ping again 1454 _, _, err = dockerCmdWithError("exec", "c0", "ping", "-c", "1", "169.254.8.8") 1455 c.Assert(err, check.IsNil) 1456 _, _, err = dockerCmdWithError("exec", "c1", "ping", "-c", "1", "169.254.9.9") 1457 c.Assert(err, check.IsNil) 1458 _, _, err = dockerCmdWithError("exec", "c2", "ping", "-c", "1", "169.254.7.7") 1459 c.Assert(err, check.IsNil) 1460 } 1461 1462 func (s *DockerSuite) TestUserDefinedNetworkConnectDisconnectLink(c *check.C) { 1463 testRequires(c, DaemonIsLinux, NotUserNamespace, NotArm) 1464 dockerCmd(c, "network", "create", "-d", "bridge", "foo1") 1465 dockerCmd(c, "network", "create", "-d", "bridge", "foo2") 1466 1467 dockerCmd(c, "run", "-d", "--net=foo1", "--name=first", "busybox", "top") 1468 c.Assert(waitRun("first"), check.IsNil) 1469 1470 // run a container in a user-defined network with a link for an existing container 1471 // and a link for a container that doesn't exist 1472 dockerCmd(c, "run", "-d", "--net=foo1", "--name=second", "--link=first:FirstInFoo1", 1473 "--link=third:bar", "busybox", "top") 1474 c.Assert(waitRun("second"), check.IsNil) 1475 1476 // ping to first and its alias FirstInFoo1 must succeed 1477 _, _, err := dockerCmdWithError("exec", "second", "ping", "-c", "1", "first") 1478 c.Assert(err, check.IsNil) 1479 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "FirstInFoo1") 1480 c.Assert(err, check.IsNil) 1481 1482 // connect first container to foo2 network 1483 dockerCmd(c, "network", "connect", "foo2", "first") 1484 // connect second container to foo2 network with a different alias for first container 1485 dockerCmd(c, "network", "connect", "--link=first:FirstInFoo2", "foo2", "second") 1486 1487 // ping the new alias in network foo2 1488 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "FirstInFoo2") 1489 c.Assert(err, check.IsNil) 1490 1491 // disconnect first container from foo1 network 1492 dockerCmd(c, "network", "disconnect", "foo1", "first") 1493 1494 // link in foo1 network must fail 1495 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "FirstInFoo1") 1496 c.Assert(err, check.NotNil) 1497 1498 // link in foo2 network must succeed 1499 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "FirstInFoo2") 1500 c.Assert(err, check.IsNil) 1501 } 1502 1503 func (s *DockerNetworkSuite) TestDockerNetworkDisconnectDefault(c *check.C) { 1504 netWorkName1 := "test1" 1505 netWorkName2 := "test2" 1506 containerName := "foo" 1507 1508 dockerCmd(c, "network", "create", netWorkName1) 1509 dockerCmd(c, "network", "create", netWorkName2) 1510 dockerCmd(c, "create", "--name", containerName, "busybox", "top") 1511 dockerCmd(c, "network", "connect", netWorkName1, containerName) 1512 dockerCmd(c, "network", "connect", netWorkName2, containerName) 1513 dockerCmd(c, "network", "disconnect", "bridge", containerName) 1514 1515 dockerCmd(c, "start", containerName) 1516 c.Assert(waitRun(containerName), checker.IsNil) 1517 networks := inspectField(c, containerName, "NetworkSettings.Networks") 1518 c.Assert(networks, checker.Contains, netWorkName1, check.Commentf(fmt.Sprintf("Should contain '%s' network", netWorkName1))) 1519 c.Assert(networks, checker.Contains, netWorkName2, check.Commentf(fmt.Sprintf("Should contain '%s' network", netWorkName2))) 1520 c.Assert(networks, checker.Not(checker.Contains), "bridge", check.Commentf("Should not contain 'bridge' network")) 1521 } 1522 1523 func (s *DockerNetworkSuite) TestDockerNetworkConnectWithAliasOnDefaultNetworks(c *check.C) { 1524 testRequires(c, DaemonIsLinux, NotUserNamespace, NotArm) 1525 1526 defaults := []string{"bridge", "host", "none"} 1527 out, _ := dockerCmd(c, "run", "-d", "--net=none", "busybox", "top") 1528 containerID := strings.TrimSpace(out) 1529 for _, net := range defaults { 1530 res, _, err := dockerCmdWithError("network", "connect", "--alias", "alias"+net, net, containerID) 1531 c.Assert(err, checker.NotNil) 1532 c.Assert(res, checker.Contains, runconfig.ErrUnsupportedNetworkAndAlias.Error()) 1533 } 1534 } 1535 1536 func (s *DockerSuite) TestUserDefinedNetworkConnectDisconnectAlias(c *check.C) { 1537 testRequires(c, DaemonIsLinux, NotUserNamespace, NotArm) 1538 dockerCmd(c, "network", "create", "-d", "bridge", "net1") 1539 dockerCmd(c, "network", "create", "-d", "bridge", "net2") 1540 1541 cid, _ := dockerCmd(c, "run", "-d", "--net=net1", "--name=first", "--net-alias=foo", "busybox:glibc", "top") 1542 c.Assert(waitRun("first"), check.IsNil) 1543 1544 dockerCmd(c, "run", "-d", "--net=net1", "--name=second", "busybox:glibc", "top") 1545 c.Assert(waitRun("second"), check.IsNil) 1546 1547 // ping first container and its alias 1548 _, _, err := dockerCmdWithError("exec", "second", "ping", "-c", "1", "first") 1549 c.Assert(err, check.IsNil) 1550 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "foo") 1551 c.Assert(err, check.IsNil) 1552 1553 // ping first container's short-id alias 1554 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", stringid.TruncateID(cid)) 1555 c.Assert(err, check.IsNil) 1556 1557 // connect first container to net2 network 1558 dockerCmd(c, "network", "connect", "--alias=bar", "net2", "first") 1559 // connect second container to foo2 network with a different alias for first container 1560 dockerCmd(c, "network", "connect", "net2", "second") 1561 1562 // ping the new alias in network foo2 1563 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "bar") 1564 c.Assert(err, check.IsNil) 1565 1566 // disconnect first container from net1 network 1567 dockerCmd(c, "network", "disconnect", "net1", "first") 1568 1569 // ping to net1 scoped alias "foo" must fail 1570 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "foo") 1571 c.Assert(err, check.NotNil) 1572 1573 // ping to net2 scoped alias "bar" must still succeed 1574 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "bar") 1575 c.Assert(err, check.IsNil) 1576 // ping to net2 scoped alias short-id must still succeed 1577 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", stringid.TruncateID(cid)) 1578 c.Assert(err, check.IsNil) 1579 1580 // verify the alias option is rejected when running on predefined network 1581 out, _, err := dockerCmdWithError("run", "--rm", "--name=any", "--net-alias=any", "busybox:glibc", "top") 1582 c.Assert(err, checker.NotNil, check.Commentf("out: %s", out)) 1583 c.Assert(out, checker.Contains, runconfig.ErrUnsupportedNetworkAndAlias.Error()) 1584 1585 // verify the alias option is rejected when connecting to predefined network 1586 out, _, err = dockerCmdWithError("network", "connect", "--alias=any", "bridge", "first") 1587 c.Assert(err, checker.NotNil, check.Commentf("out: %s", out)) 1588 c.Assert(out, checker.Contains, runconfig.ErrUnsupportedNetworkAndAlias.Error()) 1589 } 1590 1591 func (s *DockerSuite) TestUserDefinedNetworkConnectivity(c *check.C) { 1592 testRequires(c, DaemonIsLinux, NotUserNamespace) 1593 dockerCmd(c, "network", "create", "-d", "bridge", "br.net1") 1594 1595 dockerCmd(c, "run", "-d", "--net=br.net1", "--name=c1.net1", "busybox:glibc", "top") 1596 c.Assert(waitRun("c1.net1"), check.IsNil) 1597 1598 dockerCmd(c, "run", "-d", "--net=br.net1", "--name=c2.net1", "busybox:glibc", "top") 1599 c.Assert(waitRun("c2.net1"), check.IsNil) 1600 1601 // ping first container by its unqualified name 1602 _, _, err := dockerCmdWithError("exec", "c2.net1", "ping", "-c", "1", "c1.net1") 1603 c.Assert(err, check.IsNil) 1604 1605 // ping first container by its qualified name 1606 _, _, err = dockerCmdWithError("exec", "c2.net1", "ping", "-c", "1", "c1.net1.br.net1") 1607 c.Assert(err, check.IsNil) 1608 1609 // ping with first qualified name masked by an additional domain. should fail 1610 _, _, err = dockerCmdWithError("exec", "c2.net1", "ping", "-c", "1", "c1.net1.br.net1.google.com") 1611 c.Assert(err, check.NotNil) 1612 } 1613 1614 func (s *DockerSuite) TestEmbeddedDNSInvalidInput(c *check.C) { 1615 testRequires(c, DaemonIsLinux, NotUserNamespace) 1616 dockerCmd(c, "network", "create", "-d", "bridge", "nw1") 1617 1618 // Sending garbage to embedded DNS shouldn't crash the daemon 1619 dockerCmd(c, "run", "-i", "--net=nw1", "--name=c1", "debian:jessie", "bash", "-c", "echo InvalidQuery > /dev/udp/127.0.0.11/53") 1620 } 1621 1622 func (s *DockerSuite) TestDockerNetworkConnectFailsNoInspectChange(c *check.C) { 1623 dockerCmd(c, "run", "-d", "--name=bb", "busybox", "top") 1624 c.Assert(waitRun("bb"), check.IsNil) 1625 defer dockerCmd(c, "stop", "bb") 1626 1627 ns0 := inspectField(c, "bb", "NetworkSettings.Networks.bridge") 1628 1629 // A failing redundant network connect should not alter current container's endpoint settings 1630 _, _, err := dockerCmdWithError("network", "connect", "bridge", "bb") 1631 c.Assert(err, check.NotNil) 1632 1633 ns1 := inspectField(c, "bb", "NetworkSettings.Networks.bridge") 1634 c.Assert(ns1, check.Equals, ns0) 1635 } 1636 1637 func (s *DockerSuite) TestDockerNetworkInternalMode(c *check.C) { 1638 dockerCmd(c, "network", "create", "--driver=bridge", "--internal", "internal") 1639 assertNwIsAvailable(c, "internal") 1640 nr := getNetworkResource(c, "internal") 1641 c.Assert(nr.Internal, checker.True) 1642 1643 dockerCmd(c, "run", "-d", "--net=internal", "--name=first", "busybox:glibc", "top") 1644 c.Assert(waitRun("first"), check.IsNil) 1645 dockerCmd(c, "run", "-d", "--net=internal", "--name=second", "busybox:glibc", "top") 1646 c.Assert(waitRun("second"), check.IsNil) 1647 out, _, err := dockerCmdWithError("exec", "first", "ping", "-W", "4", "-c", "1", "8.8.8.8") 1648 c.Assert(err, check.NotNil) 1649 c.Assert(out, checker.Contains, "100% packet loss") 1650 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "first") 1651 c.Assert(err, check.IsNil) 1652 } 1653 1654 // Test for #21401 1655 func (s *DockerNetworkSuite) TestDockerNetworkCreateDeleteSpecialCharacters(c *check.C) { 1656 dockerCmd(c, "network", "create", "test@#$") 1657 assertNwIsAvailable(c, "test@#$") 1658 dockerCmd(c, "network", "rm", "test@#$") 1659 assertNwNotAvailable(c, "test@#$") 1660 1661 dockerCmd(c, "network", "create", "kiwl$%^") 1662 assertNwIsAvailable(c, "kiwl$%^") 1663 dockerCmd(c, "network", "rm", "kiwl$%^") 1664 assertNwNotAvailable(c, "kiwl$%^") 1665 } 1666 1667 func (s *DockerDaemonSuite) TestDaemonRestartRestoreBridgeNetwork(t *check.C) { 1668 testRequires(t, DaemonIsLinux) 1669 s.d.StartWithBusybox(t, "--live-restore") 1670 defer s.d.Stop(t) 1671 oldCon := "old" 1672 1673 _, err := s.d.Cmd("run", "-d", "--name", oldCon, "-p", "80:80", "busybox", "top") 1674 if err != nil { 1675 t.Fatal(err) 1676 } 1677 oldContainerIP, err := s.d.Cmd("inspect", "-f", "{{ .NetworkSettings.Networks.bridge.IPAddress }}", oldCon) 1678 if err != nil { 1679 t.Fatal(err) 1680 } 1681 // Kill the daemon 1682 if err := s.d.Kill(); err != nil { 1683 t.Fatal(err) 1684 } 1685 1686 // restart the daemon 1687 s.d.Start(t, "--live-restore") 1688 1689 // start a new container, the new container's ip should not be the same with 1690 // old running container. 1691 newCon := "new" 1692 _, err = s.d.Cmd("run", "-d", "--name", newCon, "busybox", "top") 1693 if err != nil { 1694 t.Fatal(err) 1695 } 1696 newContainerIP, err := s.d.Cmd("inspect", "-f", "{{ .NetworkSettings.Networks.bridge.IPAddress }}", newCon) 1697 if err != nil { 1698 t.Fatal(err) 1699 } 1700 if strings.Compare(strings.TrimSpace(oldContainerIP), strings.TrimSpace(newContainerIP)) == 0 { 1701 t.Fatalf("new container ip should not equal to old running container ip") 1702 } 1703 1704 // start a new container, the new container should ping old running container 1705 _, err = s.d.Cmd("run", "-t", "busybox", "ping", "-c", "1", oldContainerIP) 1706 if err != nil { 1707 t.Fatal(err) 1708 } 1709 1710 // start a new container, trying to publish port 80:80 should fail 1711 out, err := s.d.Cmd("run", "-p", "80:80", "-d", "busybox", "top") 1712 if err == nil || !strings.Contains(out, "Bind for 0.0.0.0:80 failed: port is already allocated") { 1713 t.Fatalf("80 port is allocated to old running container, it should failed on allocating to new container") 1714 } 1715 1716 // kill old running container and try to allocate again 1717 _, err = s.d.Cmd("kill", oldCon) 1718 if err != nil { 1719 t.Fatal(err) 1720 } 1721 id, err := s.d.Cmd("run", "-p", "80:80", "-d", "busybox", "top") 1722 if err != nil { 1723 t.Fatal(err) 1724 } 1725 1726 // Cleanup because these containers will not be shut down by daemon 1727 out, err = s.d.Cmd("stop", newCon) 1728 if err != nil { 1729 t.Fatalf("err: %v %v", err, string(out)) 1730 } 1731 _, err = s.d.Cmd("stop", strings.TrimSpace(id)) 1732 if err != nil { 1733 t.Fatal(err) 1734 } 1735 } 1736 1737 func (s *DockerNetworkSuite) TestDockerNetworkFlagAlias(c *check.C) { 1738 dockerCmd(c, "network", "create", "user") 1739 output, status := dockerCmd(c, "run", "--rm", "--network=user", "--network-alias=foo", "busybox", "true") 1740 c.Assert(status, checker.Equals, 0, check.Commentf("unexpected status code %d (%s)", status, output)) 1741 1742 output, status, _ = dockerCmdWithError("run", "--rm", "--net=user", "--network=user", "busybox", "true") 1743 c.Assert(status, checker.Equals, 0, check.Commentf("unexpected status code %d (%s)", status, output)) 1744 1745 output, status, _ = dockerCmdWithError("run", "--rm", "--network=user", "--net-alias=foo", "--network-alias=bar", "busybox", "true") 1746 c.Assert(status, checker.Equals, 0, check.Commentf("unexpected status code %d (%s)", status, output)) 1747 } 1748 1749 func (s *DockerNetworkSuite) TestDockerNetworkValidateIP(c *check.C) { 1750 _, _, err := dockerCmdWithError("network", "create", "--ipv6", "--subnet=172.28.0.0/16", "--subnet=2001:db8:1234::/64", "mynet") 1751 c.Assert(err, check.IsNil) 1752 assertNwIsAvailable(c, "mynet") 1753 1754 _, _, err = dockerCmdWithError("run", "-d", "--name", "mynet0", "--net=mynet", "--ip", "172.28.99.88", "--ip6", "2001:db8:1234::9988", "busybox", "top") 1755 c.Assert(err, check.IsNil) 1756 c.Assert(waitRun("mynet0"), check.IsNil) 1757 verifyIPAddressConfig(c, "mynet0", "mynet", "172.28.99.88", "2001:db8:1234::9988") 1758 verifyIPAddresses(c, "mynet0", "mynet", "172.28.99.88", "2001:db8:1234::9988") 1759 1760 _, _, err = dockerCmdWithError("run", "--net=mynet", "--ip", "mynet_ip", "--ip6", "2001:db8:1234::9999", "busybox", "top") 1761 c.Assert(err.Error(), checker.Contains, "invalid IPv4 address") 1762 _, _, err = dockerCmdWithError("run", "--net=mynet", "--ip", "172.28.99.99", "--ip6", "mynet_ip6", "busybox", "top") 1763 c.Assert(err.Error(), checker.Contains, "invalid IPv6 address") 1764 // This is a case of IPv4 address to `--ip6` 1765 _, _, err = dockerCmdWithError("run", "--net=mynet", "--ip6", "172.28.99.99", "busybox", "top") 1766 c.Assert(err.Error(), checker.Contains, "invalid IPv6 address") 1767 // This is a special case of an IPv4-mapped IPv6 address 1768 _, _, err = dockerCmdWithError("run", "--net=mynet", "--ip6", "::ffff:172.28.99.99", "busybox", "top") 1769 c.Assert(err.Error(), checker.Contains, "invalid IPv6 address") 1770 } 1771 1772 // Test case for 26220 1773 func (s *DockerNetworkSuite) TestDockerNetworkDisconnectFromBridge(c *check.C) { 1774 out, _ := dockerCmd(c, "network", "inspect", "--format", "{{.Id}}", "bridge") 1775 1776 network := strings.TrimSpace(out) 1777 1778 name := "test" 1779 dockerCmd(c, "create", "--name", name, "busybox", "top") 1780 1781 _, _, err := dockerCmdWithError("network", "disconnect", network, name) 1782 c.Assert(err, check.IsNil) 1783 } 1784 1785 // TestConntrackFlowsLeak covers the failure scenario of ticket: https://github.com/docker/docker/issues/8795 1786 // Validates that conntrack is correctly cleaned once a container is destroyed 1787 func (s *DockerNetworkSuite) TestConntrackFlowsLeak(c *check.C) { 1788 testRequires(c, IsAmd64, DaemonIsLinux, Network, testEnv.IsLocalDaemon) 1789 1790 // Create a new network 1791 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") 1792 assertNwIsAvailable(c, "testbind") 1793 1794 // Launch the server, this will remain listening on an exposed port and reply to any request in a ping/pong fashion 1795 cmd := "while true; do echo hello | nc -w 1 -lu 8080; done" 1796 cli.DockerCmd(c, "run", "-d", "--name", "server", "--net", "testbind", "-p", "8080:8080/udp", "appropriate/nc", "sh", "-c", cmd) 1797 1798 // Launch a container client, here the objective is to create a flow that is natted in order to expose the bug 1799 cmd = "echo world | nc -q 1 -u 192.168.10.1 8080" 1800 cli.DockerCmd(c, "run", "-d", "--name", "client", "--net=host", "appropriate/nc", "sh", "-c", cmd) 1801 1802 // Get all the flows using netlink 1803 flows, err := netlink.ConntrackTableList(netlink.ConntrackTable, unix.AF_INET) 1804 c.Assert(err, check.IsNil) 1805 var flowMatch int 1806 for _, flow := range flows { 1807 // count only the flows that we are interested in, skipping others that can be laying around the host 1808 if flow.Forward.Protocol == unix.IPPROTO_UDP && 1809 flow.Forward.DstIP.Equal(net.ParseIP("192.168.10.1")) && 1810 flow.Forward.DstPort == 8080 { 1811 flowMatch++ 1812 } 1813 } 1814 // The client should have created only 1 flow 1815 c.Assert(flowMatch, checker.Equals, 1) 1816 1817 // Now delete the server, this will trigger the conntrack cleanup 1818 cli.DockerCmd(c, "rm", "-fv", "server") 1819 1820 // Fetch again all the flows and validate that there is no server flow in the conntrack laying around 1821 flows, err = netlink.ConntrackTableList(netlink.ConntrackTable, unix.AF_INET) 1822 c.Assert(err, check.IsNil) 1823 flowMatch = 0 1824 for _, flow := range flows { 1825 if flow.Forward.Protocol == unix.IPPROTO_UDP && 1826 flow.Forward.DstIP.Equal(net.ParseIP("192.168.10.1")) && 1827 flow.Forward.DstPort == 8080 { 1828 flowMatch++ 1829 } 1830 } 1831 // All the flows have to be gone 1832 c.Assert(flowMatch, checker.Equals, 0) 1833 }