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