github.com/flavio/docker@v0.1.3-0.20170117145210-f63d1a6eec47/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 "path/filepath" 14 "strings" 15 "time" 16 17 "github.com/docker/docker/api/types" 18 "github.com/docker/docker/api/types/versions/v1p20" 19 "github.com/docker/docker/integration-cli/checker" 20 "github.com/docker/docker/integration-cli/daemon" 21 "github.com/docker/docker/pkg/stringid" 22 icmd "github.com/docker/docker/pkg/testutil/cmd" 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 ) 32 33 const dummyNetworkDriver = "dummy-network-driver" 34 const dummyIPAMDriver = "dummy-ipam-driver" 35 36 var remoteDriverNetworkRequest remoteapi.CreateNetworkRequest 37 38 func init() { 39 check.Suite(&DockerNetworkSuite{ 40 ds: &DockerSuite{}, 41 }) 42 } 43 44 type DockerNetworkSuite struct { 45 server *httptest.Server 46 ds *DockerSuite 47 d *daemon.Daemon 48 } 49 50 func (s *DockerNetworkSuite) SetUpTest(c *check.C) { 51 s.d = daemon.New(c, dockerBinary, dockerdBinary, daemon.Config{ 52 Experimental: testEnv.ExperimentalDaemon(), 53 }) 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 *DockerSuite) TestNetworkLsFormat(c *check.C) { 290 testRequires(c, DaemonIsLinux) 291 out, _ := dockerCmd(c, "network", "ls", "--format", "{{.Name}}") 292 lines := strings.Split(strings.TrimSpace(string(out)), "\n") 293 294 expected := []string{"bridge", "host", "none"} 295 var names []string 296 names = append(names, lines...) 297 c.Assert(expected, checker.DeepEquals, names, check.Commentf("Expected array with truncated names: %v, got: %v", expected, names)) 298 } 299 300 func (s *DockerSuite) TestNetworkLsFormatDefaultFormat(c *check.C) { 301 testRequires(c, DaemonIsLinux) 302 303 config := `{ 304 "networksFormat": "{{ .Name }} default" 305 }` 306 d, err := ioutil.TempDir("", "integration-cli-") 307 c.Assert(err, checker.IsNil) 308 defer os.RemoveAll(d) 309 310 err = ioutil.WriteFile(filepath.Join(d, "config.json"), []byte(config), 0644) 311 c.Assert(err, checker.IsNil) 312 313 out, _ := dockerCmd(c, "--config", d, "network", "ls") 314 lines := strings.Split(strings.TrimSpace(string(out)), "\n") 315 316 expected := []string{"bridge default", "host default", "none default"} 317 var names []string 318 names = append(names, lines...) 319 c.Assert(expected, checker.DeepEquals, names, check.Commentf("Expected array with truncated names: %v, got: %v", expected, names)) 320 } 321 322 func (s *DockerNetworkSuite) TestDockerNetworkCreatePredefined(c *check.C) { 323 predefined := []string{"bridge", "host", "none", "default"} 324 for _, net := range predefined { 325 // predefined networks can't be created again 326 out, _, err := dockerCmdWithError("network", "create", net) 327 c.Assert(err, checker.NotNil, check.Commentf("%v", out)) 328 } 329 } 330 331 func (s *DockerNetworkSuite) TestDockerNetworkCreateHostBind(c *check.C) { 332 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") 333 assertNwIsAvailable(c, "testbind") 334 335 out, _ := runSleepingContainer(c, "--net=testbind", "-p", "5000:5000") 336 id := strings.TrimSpace(out) 337 c.Assert(waitRun(id), checker.IsNil) 338 out, _ = dockerCmd(c, "ps") 339 c.Assert(out, checker.Contains, "192.168.10.1:5000->5000/tcp") 340 } 341 342 func (s *DockerNetworkSuite) TestDockerNetworkRmPredefined(c *check.C) { 343 predefined := []string{"bridge", "host", "none", "default"} 344 for _, net := range predefined { 345 // predefined networks can't be removed 346 out, _, err := dockerCmdWithError("network", "rm", net) 347 c.Assert(err, checker.NotNil, check.Commentf("%v", out)) 348 } 349 } 350 351 func (s *DockerNetworkSuite) TestDockerNetworkLsFilter(c *check.C) { 352 testNet := "testnet1" 353 testLabel := "foo" 354 testValue := "bar" 355 out, _ := dockerCmd(c, "network", "create", "dev") 356 defer func() { 357 dockerCmd(c, "network", "rm", "dev") 358 dockerCmd(c, "network", "rm", testNet) 359 }() 360 networkID := strings.TrimSpace(out) 361 362 // filter with partial ID 363 // only show 'dev' network 364 out, _ = dockerCmd(c, "network", "ls", "-f", "id="+networkID[0:5]) 365 assertNwList(c, out, []string{"dev"}) 366 367 out, _ = dockerCmd(c, "network", "ls", "-f", "name=dge") 368 assertNwList(c, out, []string{"bridge"}) 369 370 // only show built-in network (bridge, none, host) 371 out, _ = dockerCmd(c, "network", "ls", "-f", "type=builtin") 372 assertNwList(c, out, []string{"bridge", "host", "none"}) 373 374 // only show custom networks (dev) 375 out, _ = dockerCmd(c, "network", "ls", "-f", "type=custom") 376 assertNwList(c, out, []string{"dev"}) 377 378 // show all networks with filter 379 // it should be equivalent of ls without option 380 out, _ = dockerCmd(c, "network", "ls", "-f", "type=custom", "-f", "type=builtin") 381 assertNwList(c, out, []string{"bridge", "dev", "host", "none"}) 382 383 out, _ = dockerCmd(c, "network", "create", "--label", testLabel+"="+testValue, testNet) 384 assertNwIsAvailable(c, testNet) 385 386 out, _ = dockerCmd(c, "network", "ls", "-f", "label="+testLabel) 387 assertNwList(c, out, []string{testNet}) 388 389 out, _ = dockerCmd(c, "network", "ls", "-f", "label="+testLabel+"="+testValue) 390 assertNwList(c, out, []string{testNet}) 391 392 out, _ = dockerCmd(c, "network", "ls", "-f", "label=nonexistent") 393 outArr := strings.Split(strings.TrimSpace(out), "\n") 394 c.Assert(len(outArr), check.Equals, 1, check.Commentf("%s\n", out)) 395 396 out, _ = dockerCmd(c, "network", "ls", "-f", "driver=null") 397 assertNwList(c, out, []string{"none"}) 398 399 out, _ = dockerCmd(c, "network", "ls", "-f", "driver=host") 400 assertNwList(c, out, []string{"host"}) 401 402 out, _ = dockerCmd(c, "network", "ls", "-f", "driver=bridge") 403 assertNwList(c, out, []string{"bridge", "dev", testNet}) 404 } 405 406 func (s *DockerNetworkSuite) TestDockerNetworkCreateDelete(c *check.C) { 407 dockerCmd(c, "network", "create", "test") 408 assertNwIsAvailable(c, "test") 409 410 dockerCmd(c, "network", "rm", "test") 411 assertNwNotAvailable(c, "test") 412 } 413 414 func (s *DockerNetworkSuite) TestDockerNetworkCreateLabel(c *check.C) { 415 testNet := "testnetcreatelabel" 416 testLabel := "foo" 417 testValue := "bar" 418 419 dockerCmd(c, "network", "create", "--label", testLabel+"="+testValue, testNet) 420 assertNwIsAvailable(c, testNet) 421 422 out, _, err := dockerCmdWithError("network", "inspect", "--format={{ .Labels."+testLabel+" }}", testNet) 423 c.Assert(err, check.IsNil) 424 c.Assert(strings.TrimSpace(out), check.Equals, testValue) 425 426 dockerCmd(c, "network", "rm", testNet) 427 assertNwNotAvailable(c, testNet) 428 } 429 430 func (s *DockerSuite) TestDockerNetworkDeleteNotExists(c *check.C) { 431 out, _, err := dockerCmdWithError("network", "rm", "test") 432 c.Assert(err, checker.NotNil, check.Commentf("%v", out)) 433 } 434 435 func (s *DockerSuite) TestDockerNetworkDeleteMultiple(c *check.C) { 436 dockerCmd(c, "network", "create", "testDelMulti0") 437 assertNwIsAvailable(c, "testDelMulti0") 438 dockerCmd(c, "network", "create", "testDelMulti1") 439 assertNwIsAvailable(c, "testDelMulti1") 440 dockerCmd(c, "network", "create", "testDelMulti2") 441 assertNwIsAvailable(c, "testDelMulti2") 442 out, _ := dockerCmd(c, "run", "-d", "--net", "testDelMulti2", "busybox", "top") 443 containerID := strings.TrimSpace(out) 444 waitRun(containerID) 445 446 // delete three networks at the same time, since testDelMulti2 447 // contains active container, its deletion should fail. 448 out, _, err := dockerCmdWithError("network", "rm", "testDelMulti0", "testDelMulti1", "testDelMulti2") 449 // err should not be nil due to deleting testDelMulti2 failed. 450 c.Assert(err, checker.NotNil, check.Commentf("out: %s", out)) 451 // testDelMulti2 should fail due to network has active endpoints 452 c.Assert(out, checker.Contains, "has active endpoints") 453 assertNwNotAvailable(c, "testDelMulti0") 454 assertNwNotAvailable(c, "testDelMulti1") 455 // testDelMulti2 can't be deleted, so it should exist 456 assertNwIsAvailable(c, "testDelMulti2") 457 } 458 459 func (s *DockerSuite) TestDockerNetworkInspect(c *check.C) { 460 out, _ := dockerCmd(c, "network", "inspect", "host") 461 networkResources := []types.NetworkResource{} 462 err := json.Unmarshal([]byte(out), &networkResources) 463 c.Assert(err, check.IsNil) 464 c.Assert(networkResources, checker.HasLen, 1) 465 466 out, _ = dockerCmd(c, "network", "inspect", "--format={{ .Name }}", "host") 467 c.Assert(strings.TrimSpace(out), check.Equals, "host") 468 } 469 470 func (s *DockerSuite) TestDockerNetworkInspectWithID(c *check.C) { 471 out, _ := dockerCmd(c, "network", "create", "test2") 472 networkID := strings.TrimSpace(out) 473 assertNwIsAvailable(c, "test2") 474 out, _ = dockerCmd(c, "network", "inspect", "--format={{ .Id }}", "test2") 475 c.Assert(strings.TrimSpace(out), check.Equals, networkID) 476 477 out, _ = dockerCmd(c, "network", "inspect", "--format={{ .ID }}", "test2") 478 c.Assert(strings.TrimSpace(out), check.Equals, networkID) 479 } 480 481 func (s *DockerSuite) TestDockerInspectMultipleNetwork(c *check.C) { 482 result := dockerCmdWithResult("network", "inspect", "host", "none") 483 c.Assert(result, icmd.Matches, icmd.Success) 484 485 networkResources := []types.NetworkResource{} 486 err := json.Unmarshal([]byte(result.Stdout()), &networkResources) 487 c.Assert(err, check.IsNil) 488 c.Assert(networkResources, checker.HasLen, 2) 489 490 // Should print an error, return an exitCode 1 *but* should print the host network 491 result = dockerCmdWithResult("network", "inspect", "host", "nonexistent") 492 c.Assert(result, icmd.Matches, icmd.Expected{ 493 ExitCode: 1, 494 Err: "Error: No such network: nonexistent", 495 Out: "host", 496 }) 497 498 networkResources = []types.NetworkResource{} 499 err = json.Unmarshal([]byte(result.Stdout()), &networkResources) 500 c.Assert(networkResources, checker.HasLen, 1) 501 502 // Should print an error and return an exitCode, nothing else 503 result = dockerCmdWithResult("network", "inspect", "nonexistent") 504 c.Assert(result, icmd.Matches, icmd.Expected{ 505 ExitCode: 1, 506 Err: "Error: No such network: nonexistent", 507 Out: "[]", 508 }) 509 } 510 511 func (s *DockerSuite) TestDockerInspectNetworkWithContainerName(c *check.C) { 512 dockerCmd(c, "network", "create", "brNetForInspect") 513 assertNwIsAvailable(c, "brNetForInspect") 514 defer func() { 515 dockerCmd(c, "network", "rm", "brNetForInspect") 516 assertNwNotAvailable(c, "brNetForInspect") 517 }() 518 519 out, _ := dockerCmd(c, "run", "-d", "--name", "testNetInspect1", "--net", "brNetForInspect", "busybox", "top") 520 c.Assert(waitRun("testNetInspect1"), check.IsNil) 521 containerID := strings.TrimSpace(out) 522 defer func() { 523 // we don't stop container by name, because we'll rename it later 524 dockerCmd(c, "stop", containerID) 525 }() 526 527 out, _ = dockerCmd(c, "network", "inspect", "brNetForInspect") 528 networkResources := []types.NetworkResource{} 529 err := json.Unmarshal([]byte(out), &networkResources) 530 c.Assert(err, check.IsNil) 531 c.Assert(networkResources, checker.HasLen, 1) 532 container, ok := networkResources[0].Containers[containerID] 533 c.Assert(ok, checker.True) 534 c.Assert(container.Name, checker.Equals, "testNetInspect1") 535 536 // rename container and check docker inspect output update 537 newName := "HappyNewName" 538 dockerCmd(c, "rename", "testNetInspect1", newName) 539 540 // check whether network inspect works properly 541 out, _ = dockerCmd(c, "network", "inspect", "brNetForInspect") 542 newNetRes := []types.NetworkResource{} 543 err = json.Unmarshal([]byte(out), &newNetRes) 544 c.Assert(err, check.IsNil) 545 c.Assert(newNetRes, checker.HasLen, 1) 546 container1, ok := newNetRes[0].Containers[containerID] 547 c.Assert(ok, checker.True) 548 c.Assert(container1.Name, checker.Equals, newName) 549 550 } 551 552 func (s *DockerNetworkSuite) TestDockerNetworkConnectDisconnect(c *check.C) { 553 dockerCmd(c, "network", "create", "test") 554 assertNwIsAvailable(c, "test") 555 nr := getNwResource(c, "test") 556 557 c.Assert(nr.Name, checker.Equals, "test") 558 c.Assert(len(nr.Containers), checker.Equals, 0) 559 560 // run a container 561 out, _ := dockerCmd(c, "run", "-d", "--name", "test", "busybox", "top") 562 c.Assert(waitRun("test"), check.IsNil) 563 containerID := strings.TrimSpace(out) 564 565 // connect the container to the test network 566 dockerCmd(c, "network", "connect", "test", containerID) 567 568 // inspect the network to make sure container is connected 569 nr = getNetworkResource(c, nr.ID) 570 c.Assert(len(nr.Containers), checker.Equals, 1) 571 c.Assert(nr.Containers[containerID], check.NotNil) 572 573 // check if container IP matches network inspect 574 ip, _, err := net.ParseCIDR(nr.Containers[containerID].IPv4Address) 575 c.Assert(err, check.IsNil) 576 containerIP := findContainerIP(c, "test", "test") 577 c.Assert(ip.String(), checker.Equals, containerIP) 578 579 // disconnect container from the network 580 dockerCmd(c, "network", "disconnect", "test", containerID) 581 nr = getNwResource(c, "test") 582 c.Assert(nr.Name, checker.Equals, "test") 583 c.Assert(len(nr.Containers), checker.Equals, 0) 584 585 // run another container 586 out, _ = dockerCmd(c, "run", "-d", "--net", "test", "--name", "test2", "busybox", "top") 587 c.Assert(waitRun("test2"), check.IsNil) 588 containerID = strings.TrimSpace(out) 589 590 nr = getNwResource(c, "test") 591 c.Assert(nr.Name, checker.Equals, "test") 592 c.Assert(len(nr.Containers), checker.Equals, 1) 593 594 // force disconnect the container to the test network 595 dockerCmd(c, "network", "disconnect", "-f", "test", containerID) 596 597 nr = getNwResource(c, "test") 598 c.Assert(nr.Name, checker.Equals, "test") 599 c.Assert(len(nr.Containers), checker.Equals, 0) 600 601 dockerCmd(c, "network", "rm", "test") 602 assertNwNotAvailable(c, "test") 603 } 604 605 func (s *DockerNetworkSuite) TestDockerNetworkIPAMMultipleNetworks(c *check.C) { 606 // test0 bridge network 607 dockerCmd(c, "network", "create", "--subnet=192.168.0.0/16", "test1") 608 assertNwIsAvailable(c, "test1") 609 610 // test2 bridge network does not overlap 611 dockerCmd(c, "network", "create", "--subnet=192.169.0.0/16", "test2") 612 assertNwIsAvailable(c, "test2") 613 614 // for networks w/o ipam specified, docker will choose proper non-overlapping subnets 615 dockerCmd(c, "network", "create", "test3") 616 assertNwIsAvailable(c, "test3") 617 dockerCmd(c, "network", "create", "test4") 618 assertNwIsAvailable(c, "test4") 619 dockerCmd(c, "network", "create", "test5") 620 assertNwIsAvailable(c, "test5") 621 622 // test network with multiple subnets 623 // bridge network doesn't support multiple subnets. hence, use a dummy driver that supports 624 625 dockerCmd(c, "network", "create", "-d", dummyNetworkDriver, "--subnet=192.168.0.0/16", "--subnet=192.170.0.0/16", "test6") 626 assertNwIsAvailable(c, "test6") 627 628 // test network with multiple subnets with valid ipam combinations 629 // also check same subnet across networks when the driver supports it. 630 dockerCmd(c, "network", "create", "-d", dummyNetworkDriver, 631 "--subnet=192.168.0.0/16", "--subnet=192.170.0.0/16", 632 "--gateway=192.168.0.100", "--gateway=192.170.0.100", 633 "--ip-range=192.168.1.0/24", 634 "--aux-address", "a=192.168.1.5", "--aux-address", "b=192.168.1.6", 635 "--aux-address", "c=192.170.1.5", "--aux-address", "d=192.170.1.6", 636 "test7") 637 assertNwIsAvailable(c, "test7") 638 639 // cleanup 640 for i := 1; i < 8; i++ { 641 dockerCmd(c, "network", "rm", fmt.Sprintf("test%d", i)) 642 } 643 } 644 645 func (s *DockerNetworkSuite) TestDockerNetworkCustomIPAM(c *check.C) { 646 // Create a bridge network using custom ipam driver 647 dockerCmd(c, "network", "create", "--ipam-driver", dummyIPAMDriver, "br0") 648 assertNwIsAvailable(c, "br0") 649 650 // Verify expected network ipam fields are there 651 nr := getNetworkResource(c, "br0") 652 c.Assert(nr.Driver, checker.Equals, "bridge") 653 c.Assert(nr.IPAM.Driver, checker.Equals, dummyIPAMDriver) 654 655 // remove network and exercise remote ipam driver 656 dockerCmd(c, "network", "rm", "br0") 657 assertNwNotAvailable(c, "br0") 658 } 659 660 func (s *DockerNetworkSuite) TestDockerNetworkIPAMOptions(c *check.C) { 661 // Create a bridge network using custom ipam driver and options 662 dockerCmd(c, "network", "create", "--ipam-driver", dummyIPAMDriver, "--ipam-opt", "opt1=drv1", "--ipam-opt", "opt2=drv2", "br0") 663 assertNwIsAvailable(c, "br0") 664 665 // Verify expected network ipam options 666 nr := getNetworkResource(c, "br0") 667 opts := nr.IPAM.Options 668 c.Assert(opts["opt1"], checker.Equals, "drv1") 669 c.Assert(opts["opt2"], checker.Equals, "drv2") 670 } 671 672 func (s *DockerNetworkSuite) TestDockerNetworkInspectDefault(c *check.C) { 673 nr := getNetworkResource(c, "none") 674 c.Assert(nr.Driver, checker.Equals, "null") 675 c.Assert(nr.Scope, checker.Equals, "local") 676 c.Assert(nr.Internal, checker.Equals, false) 677 c.Assert(nr.EnableIPv6, checker.Equals, false) 678 c.Assert(nr.IPAM.Driver, checker.Equals, "default") 679 c.Assert(len(nr.IPAM.Config), checker.Equals, 0) 680 681 nr = getNetworkResource(c, "host") 682 c.Assert(nr.Driver, checker.Equals, "host") 683 c.Assert(nr.Scope, checker.Equals, "local") 684 c.Assert(nr.Internal, checker.Equals, false) 685 c.Assert(nr.EnableIPv6, checker.Equals, false) 686 c.Assert(nr.IPAM.Driver, checker.Equals, "default") 687 c.Assert(len(nr.IPAM.Config), checker.Equals, 0) 688 689 nr = getNetworkResource(c, "bridge") 690 c.Assert(nr.Driver, checker.Equals, "bridge") 691 c.Assert(nr.Scope, checker.Equals, "local") 692 c.Assert(nr.Internal, checker.Equals, false) 693 c.Assert(nr.EnableIPv6, checker.Equals, false) 694 c.Assert(nr.IPAM.Driver, checker.Equals, "default") 695 c.Assert(len(nr.IPAM.Config), checker.Equals, 1) 696 c.Assert(nr.IPAM.Config[0].Subnet, checker.NotNil) 697 c.Assert(nr.IPAM.Config[0].Gateway, checker.NotNil) 698 } 699 700 func (s *DockerNetworkSuite) TestDockerNetworkInspectCustomUnspecified(c *check.C) { 701 // if unspecified, network subnet will be selected from inside preferred pool 702 dockerCmd(c, "network", "create", "test01") 703 assertNwIsAvailable(c, "test01") 704 705 nr := getNetworkResource(c, "test01") 706 c.Assert(nr.Driver, checker.Equals, "bridge") 707 c.Assert(nr.Scope, checker.Equals, "local") 708 c.Assert(nr.Internal, checker.Equals, false) 709 c.Assert(nr.EnableIPv6, checker.Equals, false) 710 c.Assert(nr.IPAM.Driver, checker.Equals, "default") 711 c.Assert(len(nr.IPAM.Config), checker.Equals, 1) 712 c.Assert(nr.IPAM.Config[0].Subnet, checker.NotNil) 713 c.Assert(nr.IPAM.Config[0].Gateway, checker.NotNil) 714 715 dockerCmd(c, "network", "rm", "test01") 716 assertNwNotAvailable(c, "test01") 717 } 718 719 func (s *DockerNetworkSuite) TestDockerNetworkInspectCustomSpecified(c *check.C) { 720 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") 721 assertNwIsAvailable(c, "br0") 722 723 nr := getNetworkResource(c, "br0") 724 c.Assert(nr.Driver, checker.Equals, "bridge") 725 c.Assert(nr.Scope, checker.Equals, "local") 726 c.Assert(nr.Internal, checker.Equals, false) 727 c.Assert(nr.EnableIPv6, checker.Equals, true) 728 c.Assert(nr.IPAM.Driver, checker.Equals, "default") 729 c.Assert(len(nr.IPAM.Config), checker.Equals, 2) 730 c.Assert(nr.IPAM.Config[0].Subnet, checker.Equals, "172.28.0.0/16") 731 c.Assert(nr.IPAM.Config[0].IPRange, checker.Equals, "172.28.5.0/24") 732 c.Assert(nr.IPAM.Config[0].Gateway, checker.Equals, "172.28.5.254") 733 c.Assert(nr.Internal, checker.False) 734 dockerCmd(c, "network", "rm", "br0") 735 assertNwNotAvailable(c, "test01") 736 } 737 738 func (s *DockerNetworkSuite) TestDockerNetworkIPAMInvalidCombinations(c *check.C) { 739 // network with ip-range out of subnet range 740 _, _, err := dockerCmdWithError("network", "create", "--subnet=192.168.0.0/16", "--ip-range=192.170.0.0/16", "test") 741 c.Assert(err, check.NotNil) 742 743 // network with multiple gateways for a single subnet 744 _, _, err = dockerCmdWithError("network", "create", "--subnet=192.168.0.0/16", "--gateway=192.168.0.1", "--gateway=192.168.0.2", "test") 745 c.Assert(err, check.NotNil) 746 747 // Multiple overlapping subnets in the same network must fail 748 _, _, err = dockerCmdWithError("network", "create", "--subnet=192.168.0.0/16", "--subnet=192.168.1.0/16", "test") 749 c.Assert(err, check.NotNil) 750 751 // overlapping subnets across networks must fail 752 // create a valid test0 network 753 dockerCmd(c, "network", "create", "--subnet=192.168.0.0/16", "test0") 754 assertNwIsAvailable(c, "test0") 755 // create an overlapping test1 network 756 _, _, err = dockerCmdWithError("network", "create", "--subnet=192.168.128.0/17", "test1") 757 c.Assert(err, check.NotNil) 758 dockerCmd(c, "network", "rm", "test0") 759 assertNwNotAvailable(c, "test0") 760 } 761 762 func (s *DockerNetworkSuite) TestDockerNetworkDriverOptions(c *check.C) { 763 dockerCmd(c, "network", "create", "-d", dummyNetworkDriver, "-o", "opt1=drv1", "-o", "opt2=drv2", "testopt") 764 assertNwIsAvailable(c, "testopt") 765 gopts := remoteDriverNetworkRequest.Options[netlabel.GenericData] 766 c.Assert(gopts, checker.NotNil) 767 opts, ok := gopts.(map[string]interface{}) 768 c.Assert(ok, checker.Equals, true) 769 c.Assert(opts["opt1"], checker.Equals, "drv1") 770 c.Assert(opts["opt2"], checker.Equals, "drv2") 771 dockerCmd(c, "network", "rm", "testopt") 772 assertNwNotAvailable(c, "testopt") 773 774 } 775 776 func (s *DockerNetworkSuite) TestDockerPluginV2NetworkDriver(c *check.C) { 777 testRequires(c, DaemonIsLinux, IsAmd64, Network) 778 779 var ( 780 npName = "tiborvass/test-docker-netplugin" 781 npTag = "latest" 782 npNameWithTag = npName + ":" + npTag 783 ) 784 _, _, err := dockerCmdWithError("plugin", "install", "--grant-all-permissions", npNameWithTag) 785 c.Assert(err, checker.IsNil) 786 787 out, _, err := dockerCmdWithError("plugin", "ls") 788 c.Assert(err, checker.IsNil) 789 c.Assert(out, checker.Contains, npName) 790 c.Assert(out, checker.Contains, npTag) 791 c.Assert(out, checker.Contains, "true") 792 793 dockerCmd(c, "network", "create", "-d", npNameWithTag, "v2net") 794 assertNwIsAvailable(c, "v2net") 795 dockerCmd(c, "network", "rm", "v2net") 796 assertNwNotAvailable(c, "v2net") 797 798 } 799 800 func (s *DockerDaemonSuite) TestDockerNetworkNoDiscoveryDefaultBridgeNetwork(c *check.C) { 801 testRequires(c, ExecSupport) 802 // On default bridge network built-in service discovery should not happen 803 hostsFile := "/etc/hosts" 804 bridgeName := "external-bridge" 805 bridgeIP := "192.169.255.254/24" 806 createInterface(c, "bridge", bridgeName, bridgeIP) 807 defer deleteInterface(c, bridgeName) 808 809 s.d.StartWithBusybox(c, "--bridge", bridgeName) 810 defer s.d.Restart(c) 811 812 // run two containers and store first container's etc/hosts content 813 out, err := s.d.Cmd("run", "-d", "busybox", "top") 814 c.Assert(err, check.IsNil) 815 cid1 := strings.TrimSpace(out) 816 defer s.d.Cmd("stop", cid1) 817 818 hosts, err := s.d.Cmd("exec", cid1, "cat", hostsFile) 819 c.Assert(err, checker.IsNil) 820 821 out, err = s.d.Cmd("run", "-d", "--name", "container2", "busybox", "top") 822 c.Assert(err, check.IsNil) 823 cid2 := strings.TrimSpace(out) 824 825 // verify first container's etc/hosts file has not changed after spawning the second named container 826 hostsPost, err := s.d.Cmd("exec", cid1, "cat", hostsFile) 827 c.Assert(err, checker.IsNil) 828 c.Assert(string(hosts), checker.Equals, string(hostsPost), 829 check.Commentf("Unexpected %s change on second container creation", hostsFile)) 830 831 // stop container 2 and verify first container's etc/hosts has not changed 832 _, err = s.d.Cmd("stop", cid2) 833 c.Assert(err, check.IsNil) 834 835 hostsPost, err = s.d.Cmd("exec", cid1, "cat", hostsFile) 836 c.Assert(err, checker.IsNil) 837 c.Assert(string(hosts), checker.Equals, string(hostsPost), 838 check.Commentf("Unexpected %s change on second container creation", hostsFile)) 839 840 // but discovery is on when connecting to non default bridge network 841 network := "anotherbridge" 842 out, err = s.d.Cmd("network", "create", network) 843 c.Assert(err, check.IsNil, check.Commentf(out)) 844 defer s.d.Cmd("network", "rm", network) 845 846 out, err = s.d.Cmd("network", "connect", network, cid1) 847 c.Assert(err, check.IsNil, check.Commentf(out)) 848 849 hosts, err = s.d.Cmd("exec", cid1, "cat", hostsFile) 850 c.Assert(err, checker.IsNil) 851 852 hostsPost, err = s.d.Cmd("exec", cid1, "cat", hostsFile) 853 c.Assert(err, checker.IsNil) 854 c.Assert(string(hosts), checker.Equals, string(hostsPost), 855 check.Commentf("Unexpected %s change on second network connection", hostsFile)) 856 } 857 858 func (s *DockerNetworkSuite) TestDockerNetworkAnonymousEndpoint(c *check.C) { 859 testRequires(c, ExecSupport, NotArm) 860 hostsFile := "/etc/hosts" 861 cstmBridgeNw := "custom-bridge-nw" 862 cstmBridgeNw1 := "custom-bridge-nw1" 863 864 dockerCmd(c, "network", "create", "-d", "bridge", cstmBridgeNw) 865 assertNwIsAvailable(c, cstmBridgeNw) 866 867 // run two anonymous containers and store their etc/hosts content 868 out, _ := dockerCmd(c, "run", "-d", "--net", cstmBridgeNw, "busybox", "top") 869 cid1 := strings.TrimSpace(out) 870 871 hosts1, err := readContainerFileWithExec(cid1, hostsFile) 872 c.Assert(err, checker.IsNil) 873 874 out, _ = dockerCmd(c, "run", "-d", "--net", cstmBridgeNw, "busybox", "top") 875 cid2 := strings.TrimSpace(out) 876 877 hosts2, err := readContainerFileWithExec(cid2, hostsFile) 878 c.Assert(err, checker.IsNil) 879 880 // verify first container etc/hosts file has not changed 881 hosts1post, err := readContainerFileWithExec(cid1, hostsFile) 882 c.Assert(err, checker.IsNil) 883 c.Assert(string(hosts1), checker.Equals, string(hosts1post), 884 check.Commentf("Unexpected %s change on anonymous container creation", hostsFile)) 885 886 // Connect the 2nd container to a new network and verify the 887 // first container /etc/hosts file still hasn't changed. 888 dockerCmd(c, "network", "create", "-d", "bridge", cstmBridgeNw1) 889 assertNwIsAvailable(c, cstmBridgeNw1) 890 891 dockerCmd(c, "network", "connect", cstmBridgeNw1, cid2) 892 893 hosts2, err = readContainerFileWithExec(cid2, hostsFile) 894 c.Assert(err, checker.IsNil) 895 896 hosts1post, err = readContainerFileWithExec(cid1, hostsFile) 897 c.Assert(err, checker.IsNil) 898 c.Assert(string(hosts1), checker.Equals, string(hosts1post), 899 check.Commentf("Unexpected %s change on container connect", hostsFile)) 900 901 // start a named container 902 cName := "AnyName" 903 out, _ = dockerCmd(c, "run", "-d", "--net", cstmBridgeNw, "--name", cName, "busybox", "top") 904 cid3 := strings.TrimSpace(out) 905 906 // verify that container 1 and 2 can ping the named container 907 dockerCmd(c, "exec", cid1, "ping", "-c", "1", cName) 908 dockerCmd(c, "exec", cid2, "ping", "-c", "1", cName) 909 910 // Stop named container and verify first two containers' etc/hosts file hasn't changed 911 dockerCmd(c, "stop", cid3) 912 hosts1post, err = readContainerFileWithExec(cid1, hostsFile) 913 c.Assert(err, checker.IsNil) 914 c.Assert(string(hosts1), checker.Equals, string(hosts1post), 915 check.Commentf("Unexpected %s change on name container creation", hostsFile)) 916 917 hosts2post, err := readContainerFileWithExec(cid2, hostsFile) 918 c.Assert(err, checker.IsNil) 919 c.Assert(string(hosts2), checker.Equals, string(hosts2post), 920 check.Commentf("Unexpected %s change on name container creation", hostsFile)) 921 922 // verify that container 1 and 2 can't ping the named container now 923 _, _, err = dockerCmdWithError("exec", cid1, "ping", "-c", "1", cName) 924 c.Assert(err, check.NotNil) 925 _, _, err = dockerCmdWithError("exec", cid2, "ping", "-c", "1", cName) 926 c.Assert(err, check.NotNil) 927 } 928 929 func (s *DockerNetworkSuite) TestDockerNetworkLinkOnDefaultNetworkOnly(c *check.C) { 930 // Legacy Link feature must work only on default network, and not across networks 931 cnt1 := "container1" 932 cnt2 := "container2" 933 network := "anotherbridge" 934 935 // Run first container on default network 936 dockerCmd(c, "run", "-d", "--name", cnt1, "busybox", "top") 937 938 // Create another network and run the second container on it 939 dockerCmd(c, "network", "create", network) 940 assertNwIsAvailable(c, network) 941 dockerCmd(c, "run", "-d", "--net", network, "--name", cnt2, "busybox", "top") 942 943 // Try launching a container on default network, linking to the first container. Must succeed 944 dockerCmd(c, "run", "-d", "--link", fmt.Sprintf("%s:%s", cnt1, cnt1), "busybox", "top") 945 946 // Try launching a container on default network, linking to the second container. Must fail 947 _, _, err := dockerCmdWithError("run", "-d", "--link", fmt.Sprintf("%s:%s", cnt2, cnt2), "busybox", "top") 948 c.Assert(err, checker.NotNil) 949 950 // Connect second container to default network. Now a container on default network can link to it 951 dockerCmd(c, "network", "connect", "bridge", cnt2) 952 dockerCmd(c, "run", "-d", "--link", fmt.Sprintf("%s:%s", cnt2, cnt2), "busybox", "top") 953 } 954 955 func (s *DockerNetworkSuite) TestDockerNetworkOverlayPortMapping(c *check.C) { 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) 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 // Verify endpoint MAC address is correctly populated in container's network settings 1024 nwn := "ov" 1025 ctn := "bb" 1026 1027 dockerCmd(c, "network", "create", "-d", dummyNetworkDriver, nwn) 1028 assertNwIsAvailable(c, nwn) 1029 1030 dockerCmd(c, "run", "-d", "--net", nwn, "--name", ctn, "busybox", "top") 1031 1032 mac := inspectField(c, ctn, "NetworkSettings.Networks."+nwn+".MacAddress") 1033 c.Assert(mac, checker.Equals, "a0:b1:c2:d3:e4:f5") 1034 } 1035 1036 func (s *DockerSuite) TestInspectAPIMultipleNetworks(c *check.C) { 1037 dockerCmd(c, "network", "create", "mybridge1") 1038 dockerCmd(c, "network", "create", "mybridge2") 1039 out, _ := dockerCmd(c, "run", "-d", "busybox", "top") 1040 id := strings.TrimSpace(out) 1041 c.Assert(waitRun(id), check.IsNil) 1042 1043 dockerCmd(c, "network", "connect", "mybridge1", id) 1044 dockerCmd(c, "network", "connect", "mybridge2", id) 1045 1046 body := getInspectBody(c, "v1.20", id) 1047 var inspect120 v1p20.ContainerJSON 1048 err := json.Unmarshal(body, &inspect120) 1049 c.Assert(err, checker.IsNil) 1050 1051 versionedIP := inspect120.NetworkSettings.IPAddress 1052 1053 body = getInspectBody(c, "v1.21", id) 1054 var inspect121 types.ContainerJSON 1055 err = json.Unmarshal(body, &inspect121) 1056 c.Assert(err, checker.IsNil) 1057 c.Assert(inspect121.NetworkSettings.Networks, checker.HasLen, 3) 1058 1059 bridge := inspect121.NetworkSettings.Networks["bridge"] 1060 c.Assert(bridge.IPAddress, checker.Equals, versionedIP) 1061 c.Assert(bridge.IPAddress, checker.Equals, inspect121.NetworkSettings.IPAddress) 1062 } 1063 1064 func connectContainerToNetworks(c *check.C, d *daemon.Daemon, cName string, nws []string) { 1065 // Run a container on the default network 1066 out, err := d.Cmd("run", "-d", "--name", cName, "busybox", "top") 1067 c.Assert(err, checker.IsNil, check.Commentf(out)) 1068 1069 // Attach the container to other networks 1070 for _, nw := range nws { 1071 out, err = d.Cmd("network", "create", nw) 1072 c.Assert(err, checker.IsNil, check.Commentf(out)) 1073 out, err = d.Cmd("network", "connect", nw, cName) 1074 c.Assert(err, checker.IsNil, check.Commentf(out)) 1075 } 1076 } 1077 1078 func verifyContainerIsConnectedToNetworks(c *check.C, d *daemon.Daemon, cName string, nws []string) { 1079 // Verify container is connected to all the networks 1080 for _, nw := range nws { 1081 out, err := d.Cmd("inspect", "-f", fmt.Sprintf("{{.NetworkSettings.Networks.%s}}", nw), cName) 1082 c.Assert(err, checker.IsNil, check.Commentf(out)) 1083 c.Assert(out, checker.Not(checker.Equals), "<no value>\n") 1084 } 1085 } 1086 1087 func (s *DockerNetworkSuite) TestDockerNetworkMultipleNetworksGracefulDaemonRestart(c *check.C) { 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 cName := "cc" 1107 nwList := []string{"nw1", "nw2", "nw3"} 1108 1109 s.d.StartWithBusybox(c) 1110 1111 connectContainerToNetworks(c, s.d, cName, nwList) 1112 verifyContainerIsConnectedToNetworks(c, s.d, cName, nwList) 1113 1114 // Kill daemon and restart 1115 c.Assert(s.d.Kill(), checker.IsNil) 1116 s.d.Restart(c) 1117 1118 // Restart container 1119 _, err := s.d.Cmd("start", cName) 1120 c.Assert(err, checker.IsNil) 1121 1122 verifyContainerIsConnectedToNetworks(c, s.d, cName, nwList) 1123 } 1124 1125 func (s *DockerNetworkSuite) TestDockerNetworkRunNetByID(c *check.C) { 1126 out, _ := dockerCmd(c, "network", "create", "one") 1127 containerOut, _, err := dockerCmdWithError("run", "-d", "--net", strings.TrimSpace(out), "busybox", "top") 1128 c.Assert(err, checker.IsNil, check.Commentf(containerOut)) 1129 } 1130 1131 func (s *DockerNetworkSuite) TestDockerNetworkHostModeUngracefulDaemonRestart(c *check.C) { 1132 testRequires(c, DaemonIsLinux, NotUserNamespace) 1133 s.d.StartWithBusybox(c) 1134 1135 // Run a few containers on host network 1136 for i := 0; i < 10; i++ { 1137 cName := fmt.Sprintf("hostc-%d", i) 1138 out, err := s.d.Cmd("run", "-d", "--name", cName, "--net=host", "--restart=always", "busybox", "top") 1139 c.Assert(err, checker.IsNil, check.Commentf(out)) 1140 1141 // verfiy container has finished starting before killing daemon 1142 err = s.d.WaitRun(cName) 1143 c.Assert(err, checker.IsNil) 1144 } 1145 1146 // Kill daemon ungracefully and restart 1147 c.Assert(s.d.Kill(), checker.IsNil) 1148 s.d.Restart(c) 1149 1150 // make sure all the containers are up and running 1151 for i := 0; i < 10; i++ { 1152 err := s.d.WaitRun(fmt.Sprintf("hostc-%d", i)) 1153 c.Assert(err, checker.IsNil) 1154 } 1155 } 1156 1157 func (s *DockerNetworkSuite) TestDockerNetworkConnectToHostFromOtherNetwork(c *check.C) { 1158 dockerCmd(c, "run", "-d", "--name", "container1", "busybox", "top") 1159 c.Assert(waitRun("container1"), check.IsNil) 1160 dockerCmd(c, "network", "disconnect", "bridge", "container1") 1161 out, _, err := dockerCmdWithError("network", "connect", "host", "container1") 1162 c.Assert(err, checker.NotNil, check.Commentf(out)) 1163 c.Assert(out, checker.Contains, runconfig.ErrConflictHostNetwork.Error()) 1164 } 1165 1166 func (s *DockerNetworkSuite) TestDockerNetworkDisconnectFromHost(c *check.C) { 1167 dockerCmd(c, "run", "-d", "--name", "container1", "--net=host", "busybox", "top") 1168 c.Assert(waitRun("container1"), check.IsNil) 1169 out, _, err := dockerCmdWithError("network", "disconnect", "host", "container1") 1170 c.Assert(err, checker.NotNil, check.Commentf("Should err out disconnect from host")) 1171 c.Assert(out, checker.Contains, runconfig.ErrConflictHostNetwork.Error()) 1172 } 1173 1174 func (s *DockerNetworkSuite) TestDockerNetworkConnectWithPortMapping(c *check.C) { 1175 testRequires(c, NotArm) 1176 dockerCmd(c, "network", "create", "test1") 1177 dockerCmd(c, "run", "-d", "--name", "c1", "-p", "5000:5000", "busybox", "top") 1178 c.Assert(waitRun("c1"), check.IsNil) 1179 dockerCmd(c, "network", "connect", "test1", "c1") 1180 } 1181 1182 func verifyPortMap(c *check.C, container, port, originalMapping string, mustBeEqual bool) { 1183 chk := checker.Equals 1184 if !mustBeEqual { 1185 chk = checker.Not(checker.Equals) 1186 } 1187 currentMapping, _ := dockerCmd(c, "port", container, port) 1188 c.Assert(currentMapping, chk, originalMapping) 1189 } 1190 1191 func (s *DockerNetworkSuite) TestDockerNetworkConnectDisconnectWithPortMapping(c *check.C) { 1192 // Connect and disconnect a container with explicit and non-explicit 1193 // host port mapping to/from networks which do cause and do not cause 1194 // the container default gateway to change, and verify docker port cmd 1195 // returns congruent information 1196 testRequires(c, NotArm) 1197 cnt := "c1" 1198 dockerCmd(c, "network", "create", "aaa") 1199 dockerCmd(c, "network", "create", "ccc") 1200 1201 dockerCmd(c, "run", "-d", "--name", cnt, "-p", "9000:90", "-p", "70", "busybox", "top") 1202 c.Assert(waitRun(cnt), check.IsNil) 1203 curPortMap, _ := dockerCmd(c, "port", cnt, "70") 1204 curExplPortMap, _ := dockerCmd(c, "port", cnt, "90") 1205 1206 // Connect to a network which causes the container's default gw switch 1207 dockerCmd(c, "network", "connect", "aaa", cnt) 1208 verifyPortMap(c, cnt, "70", curPortMap, false) 1209 verifyPortMap(c, cnt, "90", curExplPortMap, true) 1210 1211 // Read current mapping 1212 curPortMap, _ = dockerCmd(c, "port", cnt, "70") 1213 1214 // Disconnect from a network which causes the container's default gw switch 1215 dockerCmd(c, "network", "disconnect", "aaa", cnt) 1216 verifyPortMap(c, cnt, "70", curPortMap, false) 1217 verifyPortMap(c, cnt, "90", curExplPortMap, true) 1218 1219 // Read current mapping 1220 curPortMap, _ = dockerCmd(c, "port", cnt, "70") 1221 1222 // Connect to a network which does not cause the container's default gw switch 1223 dockerCmd(c, "network", "connect", "ccc", cnt) 1224 verifyPortMap(c, cnt, "70", curPortMap, true) 1225 verifyPortMap(c, cnt, "90", curExplPortMap, true) 1226 } 1227 1228 func (s *DockerNetworkSuite) TestDockerNetworkConnectWithMac(c *check.C) { 1229 macAddress := "02:42:ac:11:00:02" 1230 dockerCmd(c, "network", "create", "mynetwork") 1231 dockerCmd(c, "run", "--name=test", "-d", "--mac-address", macAddress, "busybox", "top") 1232 c.Assert(waitRun("test"), check.IsNil) 1233 mac1 := inspectField(c, "test", "NetworkSettings.Networks.bridge.MacAddress") 1234 c.Assert(strings.TrimSpace(mac1), checker.Equals, macAddress) 1235 dockerCmd(c, "network", "connect", "mynetwork", "test") 1236 mac2 := inspectField(c, "test", "NetworkSettings.Networks.mynetwork.MacAddress") 1237 c.Assert(strings.TrimSpace(mac2), checker.Not(checker.Equals), strings.TrimSpace(mac1)) 1238 } 1239 1240 func (s *DockerNetworkSuite) TestDockerNetworkInspectCreatedContainer(c *check.C) { 1241 dockerCmd(c, "create", "--name", "test", "busybox") 1242 networks := inspectField(c, "test", "NetworkSettings.Networks") 1243 c.Assert(networks, checker.Contains, "bridge", check.Commentf("Should return 'bridge' network")) 1244 } 1245 1246 func (s *DockerNetworkSuite) TestDockerNetworkRestartWithMultipleNetworks(c *check.C) { 1247 dockerCmd(c, "network", "create", "test") 1248 dockerCmd(c, "run", "--name=foo", "-d", "busybox", "top") 1249 c.Assert(waitRun("foo"), checker.IsNil) 1250 dockerCmd(c, "network", "connect", "test", "foo") 1251 dockerCmd(c, "restart", "foo") 1252 networks := inspectField(c, "foo", "NetworkSettings.Networks") 1253 c.Assert(networks, checker.Contains, "bridge", check.Commentf("Should contain 'bridge' network")) 1254 c.Assert(networks, checker.Contains, "test", check.Commentf("Should contain 'test' network")) 1255 } 1256 1257 func (s *DockerNetworkSuite) TestDockerNetworkConnectDisconnectToStoppedContainer(c *check.C) { 1258 dockerCmd(c, "network", "create", "test") 1259 dockerCmd(c, "create", "--name=foo", "busybox", "top") 1260 dockerCmd(c, "network", "connect", "test", "foo") 1261 networks := inspectField(c, "foo", "NetworkSettings.Networks") 1262 c.Assert(networks, checker.Contains, "test", check.Commentf("Should contain 'test' network")) 1263 1264 // Restart docker daemon to test the config has persisted to disk 1265 s.d.Restart(c) 1266 networks = inspectField(c, "foo", "NetworkSettings.Networks") 1267 c.Assert(networks, checker.Contains, "test", check.Commentf("Should contain 'test' network")) 1268 1269 // start the container and test if we can ping it from another container in the same network 1270 dockerCmd(c, "start", "foo") 1271 c.Assert(waitRun("foo"), checker.IsNil) 1272 ip := inspectField(c, "foo", "NetworkSettings.Networks.test.IPAddress") 1273 ip = strings.TrimSpace(ip) 1274 dockerCmd(c, "run", "--net=test", "busybox", "sh", "-c", fmt.Sprintf("ping -c 1 %s", ip)) 1275 1276 dockerCmd(c, "stop", "foo") 1277 1278 // Test disconnect 1279 dockerCmd(c, "network", "disconnect", "test", "foo") 1280 networks = inspectField(c, "foo", "NetworkSettings.Networks") 1281 c.Assert(networks, checker.Not(checker.Contains), "test", check.Commentf("Should not contain 'test' network")) 1282 1283 // Restart docker daemon to test the config has persisted to disk 1284 s.d.Restart(c) 1285 networks = inspectField(c, "foo", "NetworkSettings.Networks") 1286 c.Assert(networks, checker.Not(checker.Contains), "test", check.Commentf("Should not contain 'test' network")) 1287 1288 } 1289 1290 func (s *DockerNetworkSuite) TestDockerNetworkDisconnectContainerNonexistingNetwork(c *check.C) { 1291 dockerCmd(c, "network", "create", "test") 1292 dockerCmd(c, "run", "--net=test", "-d", "--name=foo", "busybox", "top") 1293 networks := inspectField(c, "foo", "NetworkSettings.Networks") 1294 c.Assert(networks, checker.Contains, "test", check.Commentf("Should contain 'test' network")) 1295 1296 // Stop container and remove network 1297 dockerCmd(c, "stop", "foo") 1298 dockerCmd(c, "network", "rm", "test") 1299 1300 // Test disconnecting stopped container from nonexisting network 1301 dockerCmd(c, "network", "disconnect", "-f", "test", "foo") 1302 networks = inspectField(c, "foo", "NetworkSettings.Networks") 1303 c.Assert(networks, checker.Not(checker.Contains), "test", check.Commentf("Should not contain 'test' network")) 1304 } 1305 1306 func (s *DockerNetworkSuite) TestDockerNetworkConnectPreferredIP(c *check.C) { 1307 // create two networks 1308 dockerCmd(c, "network", "create", "--ipv6", "--subnet=172.28.0.0/16", "--subnet=2001:db8:1234::/64", "n0") 1309 assertNwIsAvailable(c, "n0") 1310 1311 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") 1312 assertNwIsAvailable(c, "n1") 1313 1314 // run a container on first network specifying the ip addresses 1315 dockerCmd(c, "run", "-d", "--name", "c0", "--net=n0", "--ip", "172.28.99.88", "--ip6", "2001:db8:1234::9988", "busybox", "top") 1316 c.Assert(waitRun("c0"), check.IsNil) 1317 verifyIPAddressConfig(c, "c0", "n0", "172.28.99.88", "2001:db8:1234::9988") 1318 verifyIPAddresses(c, "c0", "n0", "172.28.99.88", "2001:db8:1234::9988") 1319 1320 // connect the container to the second network specifying an ip addresses 1321 dockerCmd(c, "network", "connect", "--ip", "172.30.55.44", "--ip6", "2001:db8:abcd::5544", "n1", "c0") 1322 verifyIPAddressConfig(c, "c0", "n1", "172.30.55.44", "2001:db8:abcd::5544") 1323 verifyIPAddresses(c, "c0", "n1", "172.30.55.44", "2001:db8:abcd::5544") 1324 1325 // Stop and restart the container 1326 dockerCmd(c, "stop", "c0") 1327 dockerCmd(c, "start", "c0") 1328 1329 // verify requested addresses are applied and configs are still there 1330 verifyIPAddressConfig(c, "c0", "n0", "172.28.99.88", "2001:db8:1234::9988") 1331 verifyIPAddresses(c, "c0", "n0", "172.28.99.88", "2001:db8:1234::9988") 1332 verifyIPAddressConfig(c, "c0", "n1", "172.30.55.44", "2001:db8:abcd::5544") 1333 verifyIPAddresses(c, "c0", "n1", "172.30.55.44", "2001:db8:abcd::5544") 1334 1335 // Still it should fail to connect to the default network with a specified IP (whatever ip) 1336 out, _, err := dockerCmdWithError("network", "connect", "--ip", "172.21.55.44", "bridge", "c0") 1337 c.Assert(err, checker.NotNil, check.Commentf("out: %s", out)) 1338 c.Assert(out, checker.Contains, runconfig.ErrUnsupportedNetworkAndIP.Error()) 1339 1340 } 1341 1342 func (s *DockerNetworkSuite) TestDockerNetworkConnectPreferredIPStoppedContainer(c *check.C) { 1343 // create a container 1344 dockerCmd(c, "create", "--name", "c0", "busybox", "top") 1345 1346 // create a network 1347 dockerCmd(c, "network", "create", "--ipv6", "--subnet=172.30.0.0/16", "--subnet=2001:db8:abcd::/64", "n0") 1348 assertNwIsAvailable(c, "n0") 1349 1350 // connect the container to the network specifying an ip addresses 1351 dockerCmd(c, "network", "connect", "--ip", "172.30.55.44", "--ip6", "2001:db8:abcd::5544", "n0", "c0") 1352 verifyIPAddressConfig(c, "c0", "n0", "172.30.55.44", "2001:db8:abcd::5544") 1353 1354 // start the container, verify config has not changed and ip addresses are assigned 1355 dockerCmd(c, "start", "c0") 1356 c.Assert(waitRun("c0"), check.IsNil) 1357 verifyIPAddressConfig(c, "c0", "n0", "172.30.55.44", "2001:db8:abcd::5544") 1358 verifyIPAddresses(c, "c0", "n0", "172.30.55.44", "2001:db8:abcd::5544") 1359 1360 // stop the container and check ip config has not changed 1361 dockerCmd(c, "stop", "c0") 1362 verifyIPAddressConfig(c, "c0", "n0", "172.30.55.44", "2001:db8:abcd::5544") 1363 } 1364 1365 func (s *DockerNetworkSuite) TestDockerNetworkUnsupportedRequiredIP(c *check.C) { 1366 // requested IP is not supported on predefined networks 1367 for _, mode := range []string{"none", "host", "bridge", "default"} { 1368 checkUnsupportedNetworkAndIP(c, mode) 1369 } 1370 1371 // requested IP is not supported on networks with no user defined subnets 1372 dockerCmd(c, "network", "create", "n0") 1373 assertNwIsAvailable(c, "n0") 1374 1375 out, _, err := dockerCmdWithError("run", "-d", "--ip", "172.28.99.88", "--net", "n0", "busybox", "top") 1376 c.Assert(err, checker.NotNil, check.Commentf("out: %s", out)) 1377 c.Assert(out, checker.Contains, runconfig.ErrUnsupportedNetworkNoSubnetAndIP.Error()) 1378 1379 out, _, err = dockerCmdWithError("run", "-d", "--ip6", "2001:db8:1234::9988", "--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 dockerCmd(c, "network", "rm", "n0") 1384 assertNwNotAvailable(c, "n0") 1385 } 1386 1387 func checkUnsupportedNetworkAndIP(c *check.C, nwMode string) { 1388 out, _, err := dockerCmdWithError("run", "-d", "--net", nwMode, "--ip", "172.28.99.88", "--ip6", "2001:db8:1234::9988", "busybox", "top") 1389 c.Assert(err, checker.NotNil, check.Commentf("out: %s", out)) 1390 c.Assert(out, checker.Contains, runconfig.ErrUnsupportedNetworkAndIP.Error()) 1391 } 1392 1393 func verifyIPAddressConfig(c *check.C, cName, nwname, ipv4, ipv6 string) { 1394 if ipv4 != "" { 1395 out := inspectField(c, cName, fmt.Sprintf("NetworkSettings.Networks.%s.IPAMConfig.IPv4Address", nwname)) 1396 c.Assert(strings.TrimSpace(out), check.Equals, ipv4) 1397 } 1398 1399 if ipv6 != "" { 1400 out := inspectField(c, cName, fmt.Sprintf("NetworkSettings.Networks.%s.IPAMConfig.IPv6Address", nwname)) 1401 c.Assert(strings.TrimSpace(out), check.Equals, ipv6) 1402 } 1403 } 1404 1405 func verifyIPAddresses(c *check.C, cName, nwname, ipv4, ipv6 string) { 1406 out := inspectField(c, cName, fmt.Sprintf("NetworkSettings.Networks.%s.IPAddress", nwname)) 1407 c.Assert(strings.TrimSpace(out), check.Equals, ipv4) 1408 1409 out = inspectField(c, cName, fmt.Sprintf("NetworkSettings.Networks.%s.GlobalIPv6Address", nwname)) 1410 c.Assert(strings.TrimSpace(out), check.Equals, ipv6) 1411 } 1412 1413 func (s *DockerNetworkSuite) TestDockerNetworkConnectLinkLocalIP(c *check.C) { 1414 // create one test network 1415 dockerCmd(c, "network", "create", "--ipv6", "--subnet=2001:db8:1234::/64", "n0") 1416 assertNwIsAvailable(c, "n0") 1417 1418 // run a container with incorrect link-local address 1419 _, _, err := dockerCmdWithError("run", "--link-local-ip", "169.253.5.5", "busybox", "top") 1420 c.Assert(err, check.NotNil) 1421 _, _, err = dockerCmdWithError("run", "--link-local-ip", "2001:db8::89", "busybox", "top") 1422 c.Assert(err, check.NotNil) 1423 1424 // run two containers with link-local ip on the test network 1425 dockerCmd(c, "run", "-d", "--name", "c0", "--net=n0", "--link-local-ip", "169.254.7.7", "--link-local-ip", "fe80::254:77", "busybox", "top") 1426 c.Assert(waitRun("c0"), check.IsNil) 1427 dockerCmd(c, "run", "-d", "--name", "c1", "--net=n0", "--link-local-ip", "169.254.8.8", "--link-local-ip", "fe80::254:88", "busybox", "top") 1428 c.Assert(waitRun("c1"), check.IsNil) 1429 1430 // run a container on the default network and connect it to the test network specifying a link-local address 1431 dockerCmd(c, "run", "-d", "--name", "c2", "busybox", "top") 1432 c.Assert(waitRun("c2"), check.IsNil) 1433 dockerCmd(c, "network", "connect", "--link-local-ip", "169.254.9.9", "n0", "c2") 1434 1435 // verify the three containers can ping each other via the link-local addresses 1436 _, _, err = dockerCmdWithError("exec", "c0", "ping", "-c", "1", "169.254.8.8") 1437 c.Assert(err, check.IsNil) 1438 _, _, err = dockerCmdWithError("exec", "c1", "ping", "-c", "1", "169.254.9.9") 1439 c.Assert(err, check.IsNil) 1440 _, _, err = dockerCmdWithError("exec", "c2", "ping", "-c", "1", "169.254.7.7") 1441 c.Assert(err, check.IsNil) 1442 1443 // Stop and restart the three containers 1444 dockerCmd(c, "stop", "c0") 1445 dockerCmd(c, "stop", "c1") 1446 dockerCmd(c, "stop", "c2") 1447 dockerCmd(c, "start", "c0") 1448 dockerCmd(c, "start", "c1") 1449 dockerCmd(c, "start", "c2") 1450 1451 // verify the ping again 1452 _, _, err = dockerCmdWithError("exec", "c0", "ping", "-c", "1", "169.254.8.8") 1453 c.Assert(err, check.IsNil) 1454 _, _, err = dockerCmdWithError("exec", "c1", "ping", "-c", "1", "169.254.9.9") 1455 c.Assert(err, check.IsNil) 1456 _, _, err = dockerCmdWithError("exec", "c2", "ping", "-c", "1", "169.254.7.7") 1457 c.Assert(err, check.IsNil) 1458 } 1459 1460 func (s *DockerSuite) TestUserDefinedNetworkConnectDisconnectLink(c *check.C) { 1461 testRequires(c, DaemonIsLinux, NotUserNamespace, NotArm) 1462 dockerCmd(c, "network", "create", "-d", "bridge", "foo1") 1463 dockerCmd(c, "network", "create", "-d", "bridge", "foo2") 1464 1465 dockerCmd(c, "run", "-d", "--net=foo1", "--name=first", "busybox", "top") 1466 c.Assert(waitRun("first"), check.IsNil) 1467 1468 // run a container in a user-defined network with a link for an existing container 1469 // and a link for a container that doesn't exist 1470 dockerCmd(c, "run", "-d", "--net=foo1", "--name=second", "--link=first:FirstInFoo1", 1471 "--link=third:bar", "busybox", "top") 1472 c.Assert(waitRun("second"), check.IsNil) 1473 1474 // ping to first and its alias FirstInFoo1 must succeed 1475 _, _, err := dockerCmdWithError("exec", "second", "ping", "-c", "1", "first") 1476 c.Assert(err, check.IsNil) 1477 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "FirstInFoo1") 1478 c.Assert(err, check.IsNil) 1479 1480 // connect first container to foo2 network 1481 dockerCmd(c, "network", "connect", "foo2", "first") 1482 // connect second container to foo2 network with a different alias for first container 1483 dockerCmd(c, "network", "connect", "--link=first:FirstInFoo2", "foo2", "second") 1484 1485 // ping the new alias in network foo2 1486 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "FirstInFoo2") 1487 c.Assert(err, check.IsNil) 1488 1489 // disconnect first container from foo1 network 1490 dockerCmd(c, "network", "disconnect", "foo1", "first") 1491 1492 // link in foo1 network must fail 1493 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "FirstInFoo1") 1494 c.Assert(err, check.NotNil) 1495 1496 // link in foo2 network must succeed 1497 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "FirstInFoo2") 1498 c.Assert(err, check.IsNil) 1499 } 1500 1501 func (s *DockerNetworkSuite) TestDockerNetworkDisconnectDefault(c *check.C) { 1502 netWorkName1 := "test1" 1503 netWorkName2 := "test2" 1504 containerName := "foo" 1505 1506 dockerCmd(c, "network", "create", netWorkName1) 1507 dockerCmd(c, "network", "create", netWorkName2) 1508 dockerCmd(c, "create", "--name", containerName, "busybox", "top") 1509 dockerCmd(c, "network", "connect", netWorkName1, containerName) 1510 dockerCmd(c, "network", "connect", netWorkName2, containerName) 1511 dockerCmd(c, "network", "disconnect", "bridge", containerName) 1512 1513 dockerCmd(c, "start", containerName) 1514 c.Assert(waitRun(containerName), checker.IsNil) 1515 networks := inspectField(c, containerName, "NetworkSettings.Networks") 1516 c.Assert(networks, checker.Contains, netWorkName1, check.Commentf(fmt.Sprintf("Should contain '%s' network", netWorkName1))) 1517 c.Assert(networks, checker.Contains, netWorkName2, check.Commentf(fmt.Sprintf("Should contain '%s' network", netWorkName2))) 1518 c.Assert(networks, checker.Not(checker.Contains), "bridge", check.Commentf("Should not contain 'bridge' network")) 1519 } 1520 1521 func (s *DockerNetworkSuite) TestDockerNetworkConnectWithAliasOnDefaultNetworks(c *check.C) { 1522 testRequires(c, DaemonIsLinux, NotUserNamespace, NotArm) 1523 1524 defaults := []string{"bridge", "host", "none"} 1525 out, _ := dockerCmd(c, "run", "-d", "--net=none", "busybox", "top") 1526 containerID := strings.TrimSpace(out) 1527 for _, net := range defaults { 1528 res, _, err := dockerCmdWithError("network", "connect", "--alias", "alias"+net, net, containerID) 1529 c.Assert(err, checker.NotNil) 1530 c.Assert(res, checker.Contains, runconfig.ErrUnsupportedNetworkAndAlias.Error()) 1531 } 1532 } 1533 1534 func (s *DockerSuite) TestUserDefinedNetworkConnectDisconnectAlias(c *check.C) { 1535 testRequires(c, DaemonIsLinux, NotUserNamespace, NotArm) 1536 dockerCmd(c, "network", "create", "-d", "bridge", "net1") 1537 dockerCmd(c, "network", "create", "-d", "bridge", "net2") 1538 1539 cid, _ := dockerCmd(c, "run", "-d", "--net=net1", "--name=first", "--net-alias=foo", "busybox", "top") 1540 c.Assert(waitRun("first"), check.IsNil) 1541 1542 dockerCmd(c, "run", "-d", "--net=net1", "--name=second", "busybox", "top") 1543 c.Assert(waitRun("second"), check.IsNil) 1544 1545 // ping first container and its alias 1546 _, _, err := dockerCmdWithError("exec", "second", "ping", "-c", "1", "first") 1547 c.Assert(err, check.IsNil) 1548 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "foo") 1549 c.Assert(err, check.IsNil) 1550 1551 // ping first container's short-id alias 1552 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", stringid.TruncateID(cid)) 1553 c.Assert(err, check.IsNil) 1554 1555 // connect first container to net2 network 1556 dockerCmd(c, "network", "connect", "--alias=bar", "net2", "first") 1557 // connect second container to foo2 network with a different alias for first container 1558 dockerCmd(c, "network", "connect", "net2", "second") 1559 1560 // ping the new alias in network foo2 1561 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "bar") 1562 c.Assert(err, check.IsNil) 1563 1564 // disconnect first container from net1 network 1565 dockerCmd(c, "network", "disconnect", "net1", "first") 1566 1567 // ping to net1 scoped alias "foo" must fail 1568 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "foo") 1569 c.Assert(err, check.NotNil) 1570 1571 // ping to net2 scoped alias "bar" must still succeed 1572 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "bar") 1573 c.Assert(err, check.IsNil) 1574 // ping to net2 scoped alias short-id must still succeed 1575 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", stringid.TruncateID(cid)) 1576 c.Assert(err, check.IsNil) 1577 1578 // verify the alias option is rejected when running on predefined network 1579 out, _, err := dockerCmdWithError("run", "--rm", "--name=any", "--net-alias=any", "busybox", "top") 1580 c.Assert(err, checker.NotNil, check.Commentf("out: %s", out)) 1581 c.Assert(out, checker.Contains, runconfig.ErrUnsupportedNetworkAndAlias.Error()) 1582 1583 // verify the alias option is rejected when connecting to predefined network 1584 out, _, err = dockerCmdWithError("network", "connect", "--alias=any", "bridge", "first") 1585 c.Assert(err, checker.NotNil, check.Commentf("out: %s", out)) 1586 c.Assert(out, checker.Contains, runconfig.ErrUnsupportedNetworkAndAlias.Error()) 1587 } 1588 1589 func (s *DockerSuite) TestUserDefinedNetworkConnectivity(c *check.C) { 1590 testRequires(c, DaemonIsLinux, NotUserNamespace) 1591 dockerCmd(c, "network", "create", "-d", "bridge", "br.net1") 1592 1593 dockerCmd(c, "run", "-d", "--net=br.net1", "--name=c1.net1", "busybox", "top") 1594 c.Assert(waitRun("c1.net1"), check.IsNil) 1595 1596 dockerCmd(c, "run", "-d", "--net=br.net1", "--name=c2.net1", "busybox", "top") 1597 c.Assert(waitRun("c2.net1"), check.IsNil) 1598 1599 // ping first container by its unqualified name 1600 _, _, err := dockerCmdWithError("exec", "c2.net1", "ping", "-c", "1", "c1.net1") 1601 c.Assert(err, check.IsNil) 1602 1603 // ping first container by its qualified name 1604 _, _, err = dockerCmdWithError("exec", "c2.net1", "ping", "-c", "1", "c1.net1.br.net1") 1605 c.Assert(err, check.IsNil) 1606 1607 // ping with first qualified name masked by an additional domain. should fail 1608 _, _, err = dockerCmdWithError("exec", "c2.net1", "ping", "-c", "1", "c1.net1.br.net1.google.com") 1609 c.Assert(err, check.NotNil) 1610 } 1611 1612 func (s *DockerSuite) TestEmbeddedDNSInvalidInput(c *check.C) { 1613 testRequires(c, DaemonIsLinux, NotUserNamespace) 1614 dockerCmd(c, "network", "create", "-d", "bridge", "nw1") 1615 1616 // Sending garbage to embedded DNS shouldn't crash the daemon 1617 dockerCmd(c, "run", "-i", "--net=nw1", "--name=c1", "debian:jessie", "bash", "-c", "echo InvalidQuery > /dev/udp/127.0.0.11/53") 1618 } 1619 1620 func (s *DockerSuite) TestDockerNetworkConnectFailsNoInspectChange(c *check.C) { 1621 dockerCmd(c, "run", "-d", "--name=bb", "busybox", "top") 1622 c.Assert(waitRun("bb"), check.IsNil) 1623 1624 ns0 := inspectField(c, "bb", "NetworkSettings.Networks.bridge") 1625 1626 // A failing redundant network connect should not alter current container's endpoint settings 1627 _, _, err := dockerCmdWithError("network", "connect", "bridge", "bb") 1628 c.Assert(err, check.NotNil) 1629 1630 ns1 := inspectField(c, "bb", "NetworkSettings.Networks.bridge") 1631 c.Assert(ns1, check.Equals, ns0) 1632 } 1633 1634 func (s *DockerSuite) TestDockerNetworkInternalMode(c *check.C) { 1635 dockerCmd(c, "network", "create", "--driver=bridge", "--internal", "internal") 1636 assertNwIsAvailable(c, "internal") 1637 nr := getNetworkResource(c, "internal") 1638 c.Assert(nr.Internal, checker.True) 1639 1640 dockerCmd(c, "run", "-d", "--net=internal", "--name=first", "busybox", "top") 1641 c.Assert(waitRun("first"), check.IsNil) 1642 dockerCmd(c, "run", "-d", "--net=internal", "--name=second", "busybox", "top") 1643 c.Assert(waitRun("second"), check.IsNil) 1644 out, _, err := dockerCmdWithError("exec", "first", "ping", "-W", "4", "-c", "1", "www.google.com") 1645 c.Assert(err, check.NotNil) 1646 c.Assert(out, checker.Contains, "ping: bad address") 1647 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "first") 1648 c.Assert(err, check.IsNil) 1649 } 1650 1651 // Test for special characters in network names. only [a-zA-Z0-9][a-zA-Z0-9_.-] are 1652 // valid characters 1653 func (s *DockerNetworkSuite) TestDockerNetworkCreateDeleteSpecialCharacters(c *check.C) { 1654 _, _, err := dockerCmdWithError("network", "create", "test@#$") 1655 c.Assert(err, check.NotNil) 1656 1657 dockerCmd(c, "network", "create", "test-1_0.net") 1658 assertNwIsAvailable(c, "test-1_0.net") 1659 dockerCmd(c, "network", "rm", "test-1_0.net") 1660 assertNwNotAvailable(c, "test-1_0.net") 1661 } 1662 1663 func (s *DockerDaemonSuite) TestDaemonRestartRestoreBridgeNetwork(t *check.C) { 1664 testRequires(t, DaemonIsLinux) 1665 s.d.StartWithBusybox(t, "--live-restore") 1666 defer s.d.Stop(t) 1667 oldCon := "old" 1668 1669 _, err := s.d.Cmd("run", "-d", "--name", oldCon, "-p", "80:80", "busybox", "top") 1670 if err != nil { 1671 t.Fatal(err) 1672 } 1673 oldContainerIP, err := s.d.Cmd("inspect", "-f", "{{ .NetworkSettings.Networks.bridge.IPAddress }}", oldCon) 1674 if err != nil { 1675 t.Fatal(err) 1676 } 1677 // Kill the daemon 1678 if err := s.d.Kill(); err != nil { 1679 t.Fatal(err) 1680 } 1681 1682 // restart the daemon 1683 s.d.Start(t, "--live-restore") 1684 1685 // start a new container, the new container's ip should not be the same with 1686 // old running container. 1687 newCon := "new" 1688 _, err = s.d.Cmd("run", "-d", "--name", newCon, "busybox", "top") 1689 if err != nil { 1690 t.Fatal(err) 1691 } 1692 newContainerIP, err := s.d.Cmd("inspect", "-f", "{{ .NetworkSettings.Networks.bridge.IPAddress }}", newCon) 1693 if err != nil { 1694 t.Fatal(err) 1695 } 1696 if strings.Compare(strings.TrimSpace(oldContainerIP), strings.TrimSpace(newContainerIP)) == 0 { 1697 t.Fatalf("new container ip should not equal to old running container ip") 1698 } 1699 1700 // start a new container, the new container should ping old running container 1701 _, err = s.d.Cmd("run", "-t", "busybox", "ping", "-c", "1", oldContainerIP) 1702 if err != nil { 1703 t.Fatal(err) 1704 } 1705 1706 // start a new container, trying to publish port 80:80 should fail 1707 out, err := s.d.Cmd("run", "-p", "80:80", "-d", "busybox", "top") 1708 if err == nil || !strings.Contains(out, "Bind for 0.0.0.0:80 failed: port is already allocated") { 1709 t.Fatalf("80 port is allocated to old running container, it should failed on allocating to new container") 1710 } 1711 1712 // kill old running container and try to allocate again 1713 _, err = s.d.Cmd("kill", oldCon) 1714 if err != nil { 1715 t.Fatal(err) 1716 } 1717 id, err := s.d.Cmd("run", "-p", "80:80", "-d", "busybox", "top") 1718 if err != nil { 1719 t.Fatal(err) 1720 } 1721 1722 // Cleanup because these containers will not be shut down by daemon 1723 out, err = s.d.Cmd("stop", newCon) 1724 if err != nil { 1725 t.Fatalf("err: %v %v", err, string(out)) 1726 } 1727 _, err = s.d.Cmd("stop", strings.TrimSpace(id)) 1728 if err != nil { 1729 t.Fatal(err) 1730 } 1731 } 1732 1733 func (s *DockerNetworkSuite) TestDockerNetworkFlagAlias(c *check.C) { 1734 dockerCmd(c, "network", "create", "user") 1735 output, status := dockerCmd(c, "run", "--rm", "--network=user", "--network-alias=foo", "busybox", "true") 1736 c.Assert(status, checker.Equals, 0, check.Commentf("unexpected status code %d (%s)", status, output)) 1737 1738 output, status, _ = dockerCmdWithError("run", "--rm", "--net=user", "--network=user", "busybox", "true") 1739 c.Assert(status, checker.Equals, 0, check.Commentf("unexpected status code %d (%s)", status, output)) 1740 1741 output, status, _ = dockerCmdWithError("run", "--rm", "--network=user", "--net-alias=foo", "--network-alias=bar", "busybox", "true") 1742 c.Assert(status, checker.Equals, 0, check.Commentf("unexpected status code %d (%s)", status, output)) 1743 } 1744 1745 func (s *DockerNetworkSuite) TestDockerNetworkValidateIP(c *check.C) { 1746 _, _, err := dockerCmdWithError("network", "create", "--ipv6", "--subnet=172.28.0.0/16", "--subnet=2001:db8:1234::/64", "mynet") 1747 c.Assert(err, check.IsNil) 1748 assertNwIsAvailable(c, "mynet") 1749 1750 _, _, err = dockerCmdWithError("run", "-d", "--name", "mynet0", "--net=mynet", "--ip", "172.28.99.88", "--ip6", "2001:db8:1234::9988", "busybox", "top") 1751 c.Assert(err, check.IsNil) 1752 c.Assert(waitRun("mynet0"), check.IsNil) 1753 verifyIPAddressConfig(c, "mynet0", "mynet", "172.28.99.88", "2001:db8:1234::9988") 1754 verifyIPAddresses(c, "mynet0", "mynet", "172.28.99.88", "2001:db8:1234::9988") 1755 1756 _, _, err = dockerCmdWithError("run", "--net=mynet", "--ip", "mynet_ip", "--ip6", "2001:db8:1234::9999", "busybox", "top") 1757 c.Assert(err.Error(), checker.Contains, "invalid IPv4 address") 1758 _, _, err = dockerCmdWithError("run", "--net=mynet", "--ip", "172.28.99.99", "--ip6", "mynet_ip6", "busybox", "top") 1759 c.Assert(err.Error(), checker.Contains, "invalid IPv6 address") 1760 // This is a case of IPv4 address to `--ip6` 1761 _, _, err = dockerCmdWithError("run", "--net=mynet", "--ip6", "172.28.99.99", "busybox", "top") 1762 c.Assert(err.Error(), checker.Contains, "invalid IPv6 address") 1763 // This is a special case of an IPv4-mapped IPv6 address 1764 _, _, err = dockerCmdWithError("run", "--net=mynet", "--ip6", "::ffff:172.28.99.99", "busybox", "top") 1765 c.Assert(err.Error(), checker.Contains, "invalid IPv6 address") 1766 } 1767 1768 // Test case for 26220 1769 func (s *DockerNetworkSuite) TestDockerNetworkDisconnectFromBridge(c *check.C) { 1770 out, _ := dockerCmd(c, "network", "inspect", "--format", "{{.Id}}", "bridge") 1771 1772 network := strings.TrimSpace(out) 1773 1774 name := "test" 1775 dockerCmd(c, "create", "--name", name, "busybox", "top") 1776 1777 _, _, err := dockerCmdWithError("network", "disconnect", network, name) 1778 c.Assert(err, check.IsNil) 1779 }