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