Browse code

Docker changes for libnetwork Sandbox

- Ground-work for integrating with user namespace support

Signed-off-by: Alessandro Boch <aboch@docker.com>

Alessandro Boch authored on 2015/09/03 08:43:28
Showing 5 changed files
... ...
@@ -392,32 +392,34 @@ func (container *Container) buildHostnameFile() error {
392 392
 	return ioutil.WriteFile(container.HostnamePath, []byte(container.Config.Hostname+"\n"), 0644)
393 393
 }
394 394
 
395
-func (container *Container) buildJoinOptions() ([]libnetwork.EndpointOption, error) {
395
+func (container *Container) buildSandboxOptions() ([]libnetwork.SandboxOption, error) {
396 396
 	var (
397
-		joinOptions []libnetwork.EndpointOption
397
+		sboxOptions []libnetwork.SandboxOption
398 398
 		err         error
399 399
 		dns         []string
400 400
 		dnsSearch   []string
401 401
 	)
402 402
 
403
-	joinOptions = append(joinOptions, libnetwork.JoinOptionHostname(container.Config.Hostname),
404
-		libnetwork.JoinOptionDomainname(container.Config.Domainname))
403
+	sboxOptions = append(sboxOptions, libnetwork.OptionHostname(container.Config.Hostname),
404
+		libnetwork.OptionDomainname(container.Config.Domainname))
405 405
 
406 406
 	if container.hostConfig.NetworkMode.IsHost() {
407
-		joinOptions = append(joinOptions, libnetwork.JoinOptionUseDefaultSandbox())
407
+		sboxOptions = append(sboxOptions, libnetwork.OptionUseDefaultSandbox())
408
+		sboxOptions = append(sboxOptions, libnetwork.OptionOriginHostsPath("/etc/hosts"))
409
+		sboxOptions = append(sboxOptions, libnetwork.OptionOriginResolvConfPath("/etc/resolv.conf"))
408 410
 	}
409 411
 
410 412
 	container.HostsPath, err = container.getRootResourcePath("hosts")
411 413
 	if err != nil {
412 414
 		return nil, err
413 415
 	}
414
-	joinOptions = append(joinOptions, libnetwork.JoinOptionHostsPath(container.HostsPath))
416
+	sboxOptions = append(sboxOptions, libnetwork.OptionHostsPath(container.HostsPath))
415 417
 
416 418
 	container.ResolvConfPath, err = container.getRootResourcePath("resolv.conf")
417 419
 	if err != nil {
418 420
 		return nil, err
419 421
 	}
420
-	joinOptions = append(joinOptions, libnetwork.JoinOptionResolvConfPath(container.ResolvConfPath))
422
+	sboxOptions = append(sboxOptions, libnetwork.OptionResolvConfPath(container.ResolvConfPath))
421 423
 
422 424
 	if len(container.hostConfig.DNS) > 0 {
423 425
 		dns = container.hostConfig.DNS
... ...
@@ -426,7 +428,7 @@ func (container *Container) buildJoinOptions() ([]libnetwork.EndpointOption, err
426 426
 	}
427 427
 
428 428
 	for _, d := range dns {
429
-		joinOptions = append(joinOptions, libnetwork.JoinOptionDNS(d))
429
+		sboxOptions = append(sboxOptions, libnetwork.OptionDNS(d))
430 430
 	}
431 431
 
432 432
 	if len(container.hostConfig.DNSSearch) > 0 {
... ...
@@ -436,7 +438,7 @@ func (container *Container) buildJoinOptions() ([]libnetwork.EndpointOption, err
436 436
 	}
437 437
 
438 438
 	for _, ds := range dnsSearch {
439
-		joinOptions = append(joinOptions, libnetwork.JoinOptionDNSSearch(ds))
439
+		sboxOptions = append(sboxOptions, libnetwork.OptionDNSSearch(ds))
440 440
 	}
441 441
 
442 442
 	if container.NetworkSettings.SecondaryIPAddresses != nil {
... ...
@@ -446,7 +448,7 @@ func (container *Container) buildJoinOptions() ([]libnetwork.EndpointOption, err
446 446
 		}
447 447
 
448 448
 		for _, a := range container.NetworkSettings.SecondaryIPAddresses {
449
-			joinOptions = append(joinOptions, libnetwork.JoinOptionExtraHost(name, a.Addr))
449
+			sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(name, a.Addr))
450 450
 		}
451 451
 	}
452 452
 
... ...
@@ -465,7 +467,7 @@ func (container *Container) buildJoinOptions() ([]libnetwork.EndpointOption, err
465 465
 		if alias != child.Name[1:] {
466 466
 			aliasList = aliasList + " " + child.Name[1:]
467 467
 		}
468
-		joinOptions = append(joinOptions, libnetwork.JoinOptionExtraHost(aliasList, child.NetworkSettings.IPAddress))
468
+		sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(aliasList, child.NetworkSettings.IPAddress))
469 469
 		if child.NetworkSettings.EndpointID != "" {
470 470
 			childEndpoints = append(childEndpoints, child.NetworkSettings.EndpointID)
471 471
 		}
... ...
@@ -474,7 +476,7 @@ func (container *Container) buildJoinOptions() ([]libnetwork.EndpointOption, err
474 474
 	for _, extraHost := range container.hostConfig.ExtraHosts {
475 475
 		// allow IPv6 addresses in extra hosts; only split on first ":"
476 476
 		parts := strings.SplitN(extraHost, ":", 2)
477
-		joinOptions = append(joinOptions, libnetwork.JoinOptionExtraHost(parts[0], parts[1]))
477
+		sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(parts[0], parts[1]))
478 478
 	}
479 479
 
480 480
 	refs := container.daemon.containerGraph().RefPaths(container.ID)
... ...
@@ -490,7 +492,7 @@ func (container *Container) buildJoinOptions() ([]libnetwork.EndpointOption, err
490 490
 
491 491
 		if c != nil && !container.daemon.configStore.DisableBridge && container.hostConfig.NetworkMode.IsPrivate() {
492 492
 			logrus.Debugf("Update /etc/hosts of %s for alias %s with ip %s", c.ID, ref.Name, container.NetworkSettings.IPAddress)
493
-			joinOptions = append(joinOptions, libnetwork.JoinOptionParentUpdate(c.NetworkSettings.EndpointID, ref.Name, container.NetworkSettings.IPAddress))
493
+			sboxOptions = append(sboxOptions, libnetwork.OptionParentUpdate(c.ID, ref.Name, container.NetworkSettings.IPAddress))
494 494
 			if c.NetworkSettings.EndpointID != "" {
495 495
 				parentEndpoints = append(parentEndpoints, c.NetworkSettings.EndpointID)
496 496
 			}
... ...
@@ -504,9 +506,9 @@ func (container *Container) buildJoinOptions() ([]libnetwork.EndpointOption, err
504 504
 		},
505 505
 	}
506 506
 
507
-	joinOptions = append(joinOptions, libnetwork.JoinOptionGeneric(linkOptions))
507
+	sboxOptions = append(sboxOptions, libnetwork.OptionGeneric(linkOptions))
508 508
 
509
-	return joinOptions, nil
509
+	return sboxOptions, nil
510 510
 }
511 511
 
512 512
 func (container *Container) buildPortMapInfo(n libnetwork.Network, ep libnetwork.Endpoint, networkSettings *network.Settings) (*network.Settings, error) {
... ...
@@ -630,12 +632,10 @@ func (container *Container) updateJoinInfo(ep libnetwork.Endpoint) error {
630 630
 		container.NetworkSettings.IPv6Gateway = epInfo.GatewayIPv6().String()
631 631
 	}
632 632
 
633
-	container.NetworkSettings.SandboxKey = epInfo.SandboxKey()
634
-
635 633
 	return nil
636 634
 }
637 635
 
638
-func (container *Container) updateNetworkSettings(n libnetwork.Network, ep libnetwork.Endpoint) error {
636
+func (container *Container) updateEndpointNetworkSettings(n libnetwork.Network, ep libnetwork.Endpoint) error {
639 637
 	networkSettings := &network.Settings{NetworkID: n.ID(), EndpointID: ep.ID()}
640 638
 
641 639
 	networkSettings, err := container.buildPortMapInfo(n, ep, networkSettings)
... ...
@@ -656,35 +656,30 @@ func (container *Container) updateNetworkSettings(n libnetwork.Network, ep libne
656 656
 	return nil
657 657
 }
658 658
 
659
+func (container *Container) updateSandboxNetworkSettings(sb libnetwork.Sandbox) error {
660
+	container.NetworkSettings.SandboxID = sb.ID()
661
+	container.NetworkSettings.SandboxKey = sb.Key()
662
+	return nil
663
+}
664
+
659 665
 // UpdateNetwork is used to update the container's network (e.g. when linked containers
660 666
 // get removed/unlinked).
661 667
 func (container *Container) updateNetwork() error {
662
-	n, err := container.daemon.netController.NetworkByID(container.NetworkSettings.NetworkID)
663
-	if err != nil {
664
-		return fmt.Errorf("error locating network id %s: %v", container.NetworkSettings.NetworkID, err)
665
-	}
668
+	ctrl := container.daemon.netController
669
+	sid := container.NetworkSettings.SandboxID
666 670
 
667
-	ep, err := n.EndpointByID(container.NetworkSettings.EndpointID)
671
+	sb, err := ctrl.SandboxByID(sid)
668 672
 	if err != nil {
669
-		return fmt.Errorf("error locating endpoint id %s: %v", container.NetworkSettings.EndpointID, err)
670
-	}
671
-
672
-	if err := ep.Leave(container.ID); err != nil {
673
-		return fmt.Errorf("endpoint leave failed: %v", err)
674
-
673
+		return fmt.Errorf("error locating sandbox id %s: %v", sid, err)
675 674
 	}
676 675
 
677
-	joinOptions, err := container.buildJoinOptions()
676
+	options, err := container.buildSandboxOptions()
678 677
 	if err != nil {
679 678
 		return fmt.Errorf("Update network failed: %v", err)
680 679
 	}
681 680
 
682
-	if err := ep.Join(container.ID, joinOptions...); err != nil {
683
-		return fmt.Errorf("endpoint join failed: %v", err)
684
-	}
685
-
686
-	if err := container.updateJoinInfo(ep); err != nil {
687
-		return fmt.Errorf("Updating join info failed: %v", err)
681
+	if err := sb.Refresh(options...); err != nil {
682
+		return fmt.Errorf("Update network failed: Failure in refresh sandbox %s: %v", sid, err)
688 683
 	}
689 684
 
690 685
 	return nil
... ...
@@ -871,6 +866,7 @@ func (container *Container) allocateNetwork() error {
871 871
 
872 872
 func (container *Container) configureNetwork(networkName, service, networkDriver string, canCreateNetwork bool) error {
873 873
 	controller := container.daemon.netController
874
+
874 875
 	n, err := controller.NetworkByName(networkName)
875 876
 	if err != nil {
876 877
 		if _, ok := err.(libnetwork.ErrNoSuchNetwork); !ok || !canCreateNetwork {
... ...
@@ -899,16 +895,32 @@ func (container *Container) configureNetwork(networkName, service, networkDriver
899 899
 		}
900 900
 	}
901 901
 
902
-	if err := container.updateNetworkSettings(n, ep); err != nil {
902
+	if err := container.updateEndpointNetworkSettings(n, ep); err != nil {
903 903
 		return err
904 904
 	}
905 905
 
906
-	joinOptions, err := container.buildJoinOptions()
907
-	if err != nil {
908
-		return err
906
+	var sb libnetwork.Sandbox
907
+	controller.WalkSandboxes(func(s libnetwork.Sandbox) bool {
908
+		if s.ContainerID() == container.ID {
909
+			sb = s
910
+			return true
911
+		}
912
+		return false
913
+	})
914
+	if sb == nil {
915
+		options, err := container.buildSandboxOptions()
916
+		if err != nil {
917
+			return err
918
+		}
919
+		sb, err = controller.NewSandbox(container.ID, options...)
920
+		if err != nil {
921
+			return err
922
+		}
909 923
 	}
910 924
 
911
-	if err := ep.Join(container.ID, joinOptions...); err != nil {
925
+	container.updateSandboxNetworkSettings(sb)
926
+
927
+	if err := ep.Join(sb); err != nil {
912 928
 		return err
913 929
 	}
914 930
 
... ...
@@ -1038,12 +1050,19 @@ func (container *Container) releaseNetwork() {
1038 1038
 		return
1039 1039
 	}
1040 1040
 
1041
+	sid := container.NetworkSettings.SandboxID
1041 1042
 	eid := container.NetworkSettings.EndpointID
1042 1043
 	nid := container.NetworkSettings.NetworkID
1043 1044
 
1044 1045
 	container.NetworkSettings = &network.Settings{}
1045 1046
 
1046
-	if nid == "" || eid == "" {
1047
+	if sid == "" || nid == "" || eid == "" {
1048
+		return
1049
+	}
1050
+
1051
+	sb, err := container.daemon.netController.SandboxByID(sid)
1052
+	if err != nil {
1053
+		logrus.Errorf("error locating sandbox id %s: %v", sid, err)
1047 1054
 		return
1048 1055
 	}
1049 1056
 
... ...
@@ -1059,17 +1078,9 @@ func (container *Container) releaseNetwork() {
1059 1059
 		return
1060 1060
 	}
1061 1061
 
1062
-	switch {
1063
-	case container.hostConfig.NetworkMode.IsHost():
1064
-		if err := ep.Leave(container.ID); err != nil {
1065
-			logrus.Errorf("Error leaving endpoint id %s for container %s: %v", eid, container.ID, err)
1066
-			return
1067
-		}
1068
-	default:
1069
-		if err := container.daemon.netController.LeaveAll(container.ID); err != nil {
1070
-			logrus.Errorf("Leave all failed for  %s: %v", container.ID, err)
1071
-			return
1072
-		}
1062
+	if err := sb.Delete(); err != nil {
1063
+		logrus.Errorf("Error deleting sandbox id %s for container %s: %v", sid, container.ID, err)
1064
+		return
1073 1065
 	}
1074 1066
 
1075 1067
 	// In addition to leaving all endpoints, delete implicitly created endpoint
... ...
@@ -13,6 +13,7 @@ type Address struct {
13 13
 type Settings struct {
14 14
 	Bridge                 string
15 15
 	EndpointID             string
16
+	SandboxID              string
16 17
 	Gateway                string
17 18
 	GlobalIPv6Address      string
18 19
 	GlobalIPv6PrefixLen    int
... ...
@@ -6,7 +6,7 @@ import (
6 6
 
7 7
 	"github.com/docker/docker/api/types"
8 8
 	"github.com/docker/docker/daemon/execdriver"
9
-	"github.com/docker/libnetwork/sandbox"
9
+	"github.com/docker/libnetwork/osl"
10 10
 	"github.com/opencontainers/runc/libcontainer"
11 11
 )
12 12
 
... ...
@@ -86,16 +86,12 @@ func (daemon *Daemon) getNetworkStats(name string) ([]*libcontainer.NetworkInter
86 86
 		return list, err
87 87
 	}
88 88
 
89
-	nw, err := daemon.netController.NetworkByID(c.NetworkSettings.NetworkID)
90
-	if err != nil {
91
-		return list, err
92
-	}
93
-	ep, err := nw.EndpointByID(c.NetworkSettings.EndpointID)
89
+	sb, err := daemon.netController.SandboxByID(c.NetworkSettings.SandboxID)
94 90
 	if err != nil {
95 91
 		return list, err
96 92
 	}
97 93
 
98
-	stats, err := ep.Statistics()
94
+	stats, err := sb.Statistics()
99 95
 	if err != nil {
100 96
 		return list, err
101 97
 	}
... ...
@@ -108,7 +104,7 @@ func (daemon *Daemon) getNetworkStats(name string) ([]*libcontainer.NetworkInter
108 108
 	return list, nil
109 109
 }
110 110
 
111
-func convertLnNetworkStats(name string, stats *sandbox.InterfaceStatistics) *libcontainer.NetworkInterface {
111
+func convertLnNetworkStats(name string, stats *osl.InterfaceStatistics) *libcontainer.NetworkInterface {
112 112
 	n := &libcontainer.NetworkInterface{Name: name}
113 113
 	n.RxBytes = stats.RxBytes
114 114
 	n.RxPackets = stats.RxPackets
... ...
@@ -1524,19 +1524,23 @@ func (s *DockerDaemonSuite) TestDaemonRestartCleanupNetns(c *check.C) {
1524 1524
 	if err != nil {
1525 1525
 		c.Fatal(out, err)
1526 1526
 	}
1527
+
1528
+	// Get sandbox key via inspect
1529
+	out, err = s.d.Cmd("inspect", "--format", "'{{.NetworkSettings.SandboxKey}}'", "netns")
1530
+	if err != nil {
1531
+		c.Fatalf("Error inspecting container: %s, %v", out, err)
1532
+	}
1533
+	fileName := strings.Trim(out, " \r\n'")
1534
+
1527 1535
 	if out, err := s.d.Cmd("stop", "netns"); err != nil {
1528 1536
 		c.Fatal(out, err)
1529 1537
 	}
1530 1538
 
1531
-	// Construct netns file name from container id
1532
-	out = strings.TrimSpace(out)
1533
-	nsFile := out[:12]
1534
-
1535 1539
 	// Test if the file still exists
1536
-	out, _, err = runCommandWithOutput(exec.Command("stat", "-c", "%n", "/var/run/docker/netns/"+nsFile))
1540
+	out, _, err = runCommandWithOutput(exec.Command("stat", "-c", "%n", fileName))
1537 1541
 	out = strings.TrimSpace(out)
1538 1542
 	c.Assert(err, check.IsNil, check.Commentf("Output: %s", out))
1539
-	c.Assert(out, check.Equals, "/var/run/docker/netns/"+nsFile, check.Commentf("Output: %s", out))
1543
+	c.Assert(out, check.Equals, fileName, check.Commentf("Output: %s", out))
1540 1544
 
1541 1545
 	// Remove the container and restart the daemon
1542 1546
 	if out, err := s.d.Cmd("rm", "netns"); err != nil {
... ...
@@ -1548,10 +1552,9 @@ func (s *DockerDaemonSuite) TestDaemonRestartCleanupNetns(c *check.C) {
1548 1548
 	}
1549 1549
 
1550 1550
 	// Test again and see now the netns file does not exist
1551
-	out, _, err = runCommandWithOutput(exec.Command("stat", "-c", "%n", "/var/run/docker/netns/"+nsFile))
1551
+	out, _, err = runCommandWithOutput(exec.Command("stat", "-c", "%n", fileName))
1552 1552
 	out = strings.TrimSpace(out)
1553 1553
 	c.Assert(err, check.Not(check.IsNil), check.Commentf("Output: %s", out))
1554
-	// c.Assert(out, check.Equals, "", check.Commentf("Output: %s", out))
1555 1554
 }
1556 1555
 
1557 1556
 // tests regression detailed in #13964 where DOCKER_TLS_VERIFY env is ignored
... ...
@@ -865,7 +865,7 @@ func (s *DockerSuite) TestRunDnsDefaultOptions(c *check.C) {
865 865
 	// check that the actual defaults are appended to the commented out
866 866
 	// localhost resolver (which should be preserved)
867 867
 	// NOTE: if we ever change the defaults from google dns, this will break
868
-	expected := "#nameserver 127.0.2.1\n\nnameserver 8.8.8.8\nnameserver 8.8.4.4"
868
+	expected := "#nameserver 127.0.2.1\n\nnameserver 8.8.8.8\nnameserver 8.8.4.4\n"
869 869
 	if actual != expected {
870 870
 		c.Fatalf("expected resolv.conf be: %q, but was: %q", expected, actual)
871 871
 	}
... ...
@@ -880,7 +880,7 @@ func (s *DockerSuite) TestRunDnsOptions(c *check.C) {
880 880
 	}
881 881
 
882 882
 	actual := strings.Replace(strings.Trim(out, "\r\n"), "\n", " ", -1)
883
-	if actual != "nameserver 127.0.0.1 search mydomain" {
883
+	if actual != "search mydomain nameserver 127.0.0.1" {
884 884
 		c.Fatalf("expected 'nameserver 127.0.0.1 search mydomain', but says: %q", actual)
885 885
 	}
886 886
 
... ...
@@ -1001,7 +1001,7 @@ func (s *DockerSuite) TestRunNonRootUserResolvName(c *check.C) {
1001 1001
 func (s *DockerSuite) TestRunResolvconfUpdate(c *check.C) {
1002 1002
 	testRequires(c, SameHostDaemon)
1003 1003
 
1004
-	tmpResolvConf := []byte("search pommesfrites.fr\nnameserver 12.34.56.78")
1004
+	tmpResolvConf := []byte("search pommesfrites.fr\nnameserver 12.34.56.78\n")
1005 1005
 	tmpLocalhostResolvConf := []byte("nameserver 127.0.0.1")
1006 1006
 
1007 1007
 	//take a copy of resolv.conf for restoring after test completes
... ...
@@ -1131,7 +1131,7 @@ func (s *DockerSuite) TestRunResolvconfUpdate(c *check.C) {
1131 1131
 		c.Fatal(err)
1132 1132
 	}
1133 1133
 
1134
-	expected := "\nnameserver 8.8.8.8\nnameserver 8.8.4.4"
1134
+	expected := "\nnameserver 8.8.8.8\nnameserver 8.8.4.4\n"
1135 1135
 	if !bytes.Equal(containerResolv, []byte(expected)) {
1136 1136
 		c.Fatalf("Container does not have cleaned/replaced DNS in resolv.conf; expected %q, got %q", expected, string(containerResolv))
1137 1137
 	}