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