瀏覽代碼

Merge pull request #19705 from mavenugo/18222

Vendor libnetwork v0.6.0-rc4 & corresponding changes in engine for port-map sandobx handling.
Arnaud Porterie 9 年之前
父節點
當前提交
269a6d7d36

+ 58 - 29
container/container_unix.go

@@ -125,18 +125,26 @@ func (container *Container) buildPortMapInfo(ep libnetwork.Endpoint) error {
 		return derr.ErrorCodeEmptyNetwork
 		return derr.ErrorCodeEmptyNetwork
 	}
 	}
 
 
+	if len(networkSettings.Ports) == 0 {
+		pm, err := getEndpointPortMapInfo(ep)
+		if err != nil {
+			return err
+		}
+		networkSettings.Ports = pm
+	}
+	return nil
+}
+
+func getEndpointPortMapInfo(ep libnetwork.Endpoint) (nat.PortMap, error) {
+	pm := nat.PortMap{}
 	driverInfo, err := ep.DriverInfo()
 	driverInfo, err := ep.DriverInfo()
 	if err != nil {
 	if err != nil {
-		return err
+		return pm, err
 	}
 	}
 
 
 	if driverInfo == nil {
 	if driverInfo == nil {
 		// It is not an error for epInfo to be nil
 		// It is not an error for epInfo to be nil
-		return nil
-	}
-
-	if networkSettings.Ports == nil {
-		networkSettings.Ports = nat.PortMap{}
+		return pm, nil
 	}
 	}
 
 
 	if expData, ok := driverInfo[netlabel.ExposedPorts]; ok {
 	if expData, ok := driverInfo[netlabel.ExposedPorts]; ok {
@@ -144,30 +152,45 @@ func (container *Container) buildPortMapInfo(ep libnetwork.Endpoint) error {
 			for _, tp := range exposedPorts {
 			for _, tp := range exposedPorts {
 				natPort, err := nat.NewPort(tp.Proto.String(), strconv.Itoa(int(tp.Port)))
 				natPort, err := nat.NewPort(tp.Proto.String(), strconv.Itoa(int(tp.Port)))
 				if err != nil {
 				if err != nil {
-					return derr.ErrorCodeParsingPort.WithArgs(tp.Port, err)
+					return pm, derr.ErrorCodeParsingPort.WithArgs(tp.Port, err)
 				}
 				}
-				networkSettings.Ports[natPort] = nil
+				pm[natPort] = nil
 			}
 			}
 		}
 		}
 	}
 	}
 
 
 	mapData, ok := driverInfo[netlabel.PortMap]
 	mapData, ok := driverInfo[netlabel.PortMap]
 	if !ok {
 	if !ok {
-		return nil
+		return pm, nil
 	}
 	}
 
 
 	if portMapping, ok := mapData.([]types.PortBinding); ok {
 	if portMapping, ok := mapData.([]types.PortBinding); ok {
 		for _, pp := range portMapping {
 		for _, pp := range portMapping {
 			natPort, err := nat.NewPort(pp.Proto.String(), strconv.Itoa(int(pp.Port)))
 			natPort, err := nat.NewPort(pp.Proto.String(), strconv.Itoa(int(pp.Port)))
 			if err != nil {
 			if err != nil {
-				return err
+				return pm, err
 			}
 			}
 			natBndg := nat.PortBinding{HostIP: pp.HostIP.String(), HostPort: strconv.Itoa(int(pp.HostPort))}
 			natBndg := nat.PortBinding{HostIP: pp.HostIP.String(), HostPort: strconv.Itoa(int(pp.HostPort))}
-			networkSettings.Ports[natPort] = append(networkSettings.Ports[natPort], natBndg)
+			pm[natPort] = append(pm[natPort], natBndg)
 		}
 		}
 	}
 	}
 
 
-	return nil
+	return pm, nil
+}
+
+func getSandboxPortMapInfo(sb libnetwork.Sandbox) nat.PortMap {
+	pm := nat.PortMap{}
+	if sb == nil {
+		return pm
+	}
+
+	for _, ep := range sb.Endpoints() {
+		pm, _ = getEndpointPortMapInfo(ep)
+		if len(pm) > 0 {
+			break
+		}
+	}
+	return pm
 }
 }
 
 
 // BuildEndpointInfo sets endpoint-related fields on container.NetworkSettings based on the provided network and endpoint.
 // BuildEndpointInfo sets endpoint-related fields on container.NetworkSettings based on the provided network and endpoint.
@@ -261,7 +284,7 @@ func (container *Container) BuildJoinOptions(n libnetwork.Network) ([]libnetwork
 }
 }
 
 
 // BuildCreateEndpointOptions builds endpoint options from a given network.
 // BuildCreateEndpointOptions builds endpoint options from a given network.
-func (container *Container) BuildCreateEndpointOptions(n libnetwork.Network, epConfig *network.EndpointSettings) ([]libnetwork.EndpointOption, error) {
+func (container *Container) BuildCreateEndpointOptions(n libnetwork.Network, epConfig *network.EndpointSettings, sb libnetwork.Sandbox) ([]libnetwork.EndpointOption, error) {
 	var (
 	var (
 		portSpecs     = make(nat.PortSet)
 		portSpecs     = make(nat.PortSet)
 		bindings      = make(nat.PortMap)
 		bindings      = make(nat.PortMap)
@@ -290,10 +313,29 @@ func (container *Container) BuildCreateEndpointOptions(n libnetwork.Network, epC
 		createOptions = append(createOptions, libnetwork.CreateOptionDisableResolution())
 		createOptions = append(createOptions, libnetwork.CreateOptionDisableResolution())
 	}
 	}
 
 
-	// Other configs are applicable only for the endpoint in the network
+	// configs that are applicable only for the endpoint in the network
 	// to which container was connected to on docker run.
 	// to which container was connected to on docker run.
-	if n.Name() != container.HostConfig.NetworkMode.NetworkName() &&
-		!(n.Name() == "bridge" && container.HostConfig.NetworkMode.IsDefault()) {
+	// Ideally all these network-specific endpoint configurations must be moved under
+	// container.NetworkSettings.Networks[n.Name()]
+	if n.Name() == container.HostConfig.NetworkMode.NetworkName() ||
+		(n.Name() == "bridge" && container.HostConfig.NetworkMode.IsDefault()) {
+		if container.Config.MacAddress != "" {
+			mac, err := net.ParseMAC(container.Config.MacAddress)
+			if err != nil {
+				return nil, err
+			}
+
+			genericOption := options.Generic{
+				netlabel.MacAddress: mac,
+			}
+
+			createOptions = append(createOptions, libnetwork.EndpointOptionGeneric(genericOption))
+		}
+	}
+
+	// Port-mapping rules belong to the container & applicable only to non-internal networks
+	portmaps := getSandboxPortMapInfo(sb)
+	if n.Info().Internal() || len(portmaps) > 0 {
 		return createOptions, nil
 		return createOptions, nil
 	}
 	}
 
 
@@ -353,19 +395,6 @@ func (container *Container) BuildCreateEndpointOptions(n libnetwork.Network, epC
 		libnetwork.CreateOptionPortMapping(pbList),
 		libnetwork.CreateOptionPortMapping(pbList),
 		libnetwork.CreateOptionExposedPorts(exposeList))
 		libnetwork.CreateOptionExposedPorts(exposeList))
 
 
-	if container.Config.MacAddress != "" {
-		mac, err := net.ParseMAC(container.Config.MacAddress)
-		if err != nil {
-			return nil, err
-		}
-
-		genericOption := options.Generic{
-			netlabel.MacAddress: mac,
-		}
-
-		createOptions = append(createOptions, libnetwork.EndpointOptionGeneric(genericOption))
-	}
-
 	return createOptions, nil
 	return createOptions, nil
 }
 }
 
 

+ 2 - 2
daemon/container_operations_unix.go

@@ -765,7 +765,8 @@ func (daemon *Daemon) connectToNetwork(container *container.Container, idOrName
 
 
 	controller := daemon.netController
 	controller := daemon.netController
 
 
-	createOptions, err := container.BuildCreateEndpointOptions(n, endpointConfig)
+	sb := daemon.getNetworkSandbox(container)
+	createOptions, err := container.BuildCreateEndpointOptions(n, endpointConfig, sb)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
@@ -791,7 +792,6 @@ func (daemon *Daemon) connectToNetwork(container *container.Container, idOrName
 		return err
 		return err
 	}
 	}
 
 
-	sb := daemon.getNetworkSandbox(container)
 	if sb == nil {
 	if sb == nil {
 		options, err := daemon.buildSandboxOptions(container, n)
 		options, err := daemon.buildSandboxOptions(container, n)
 		if err != nil {
 		if err != nil {

+ 1 - 1
hack/vendor.sh

@@ -27,7 +27,7 @@ clone git github.com/RackSec/srslog 6eb773f331e46fbba8eecb8e794e635e75fc04de
 clone git github.com/imdario/mergo 0.2.1
 clone git github.com/imdario/mergo 0.2.1
 
 
 #get libnetwork packages
 #get libnetwork packages
-clone git github.com/docker/libnetwork v0.6.0-rc3
+clone git github.com/docker/libnetwork v0.6.0-rc4
 clone git github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
 clone git github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
 clone git github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b
 clone git github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b
 clone git github.com/hashicorp/memberlist 9a1e242e454d2443df330bdd51a436d5a9058fc4
 clone git github.com/hashicorp/memberlist 9a1e242e454d2443df330bdd51a436d5a9058fc4

+ 21 - 0
integration-cli/docker_cli_port_test.go

@@ -293,3 +293,24 @@ func (s *DockerSuite) TestPortExposeHostBinding(c *check.C) {
 	// Port is still bound after the Container is removed
 	// Port is still bound after the Container is removed
 	c.Assert(err, checker.NotNil, check.Commentf("out: %s", out))
 	c.Assert(err, checker.NotNil, check.Commentf("out: %s", out))
 }
 }
+
+func (s *DockerSuite) TestPortBindingOnSandbox(c *check.C) {
+	testRequires(c, DaemonIsLinux, NotUserNamespace)
+	dockerCmd(c, "network", "create", "--internal", "-d", "bridge", "internal-net")
+	dockerCmd(c, "run", "--net", "internal-net", "-d", "--name", "c1",
+		"-p", "8080:8080", "busybox", "nc", "-l", "-p", "8080")
+	c.Assert(waitRun("c1"), check.IsNil)
+
+	_, _, err := dockerCmdWithError("run", "--net=host", "busybox", "nc", "localhost", "8080")
+	c.Assert(err, check.NotNil,
+		check.Commentf("Port mapping on internal network is expected to fail"))
+
+	// Connect container to another normal bridge network
+	dockerCmd(c, "network", "create", "-d", "bridge", "foo-net")
+	dockerCmd(c, "network", "connect", "foo-net", "c1")
+
+	_, _, err = dockerCmdWithError("run", "--net=host", "busybox", "nc", "localhost", "8080")
+	c.Assert(err, check.IsNil,
+		check.Commentf("Port mapping on the new network is expected to succeed"))
+
+}

+ 4 - 0
vendor/src/github.com/docker/libnetwork/CHANGELOG.md

@@ -1,5 +1,9 @@
 # Changelog
 # Changelog
 
 
+## 0.6.0-rc4 (2016-01-25)
+- Add Endpoints() API to Sandbox interface
+- Fixed a race-condition in default gateway network creation
+
 ## 0.6.0-rc3 (2016-01-25)
 ## 0.6.0-rc3 (2016-01-25)
 - Fixes docker/docker#19576
 - Fixes docker/docker#19576
 - Fixed embedded DNS to listen in TCP as well
 - Fixed embedded DNS to listen in TCP as well

+ 20 - 5
vendor/src/github.com/docker/libnetwork/default_gateway.go

@@ -12,6 +12,8 @@ const (
 	gwEPlen       = 12
 	gwEPlen       = 12
 )
 )
 
 
+var procGwNetwork = make(chan (bool), 1)
+
 /*
 /*
    libnetwork creates a bridge network "docker_gw_bridge" for provding
    libnetwork creates a bridge network "docker_gw_bridge" for provding
    default gateway for the containers if none of the container's endpoints
    default gateway for the containers if none of the container's endpoints
@@ -35,13 +37,11 @@ func (sb *sandbox) setupDefaultGW(srcEp *endpoint) error {
 		return nil
 		return nil
 	}
 	}
 
 
+	// Look for default gw network. In case of error (includes not found),
+	// retry and create it if needed in a serialized execution.
 	n, err := c.NetworkByName(libnGWNetwork)
 	n, err := c.NetworkByName(libnGWNetwork)
 	if err != nil {
 	if err != nil {
-		if _, ok := err.(types.NotFoundError); !ok {
-			return err
-		}
-		n, err = c.createGWNetwork()
-		if err != nil {
+		if n, err = c.defaultGwNetwork(); err != nil {
 			return err
 			return err
 		}
 		}
 	}
 	}
@@ -150,3 +150,18 @@ func (sb *sandbox) getEPwithoutGateway() *endpoint {
 	}
 	}
 	return nil
 	return nil
 }
 }
+
+// Looks for the default gw network and creates it if not there.
+// Parallel executions are serialized.
+func (c *controller) defaultGwNetwork() (Network, error) {
+	procGwNetwork <- true
+	defer func() { <-procGwNetwork }()
+
+	n, err := c.NetworkByName(libnGWNetwork)
+	if err != nil {
+		if _, ok := err.(types.NotFoundError); ok {
+			n, err = c.createGWNetwork()
+		}
+	}
+	return n, err
+}

+ 13 - 0
vendor/src/github.com/docker/libnetwork/sandbox.go

@@ -47,6 +47,8 @@ type Sandbox interface {
 	// ResolveIP returns the service name for the passed in IP. IP is in reverse dotted
 	// ResolveIP returns the service name for the passed in IP. IP is in reverse dotted
 	// notation; the format used for DNS PTR records
 	// notation; the format used for DNS PTR records
 	ResolveIP(name string) string
 	ResolveIP(name string) string
+	// Endpoints returns all the endpoints connected to the sandbox
+	Endpoints() []Endpoint
 }
 }
 
 
 // SandboxOption is a option setter function type used to pass varios options to
 // SandboxOption is a option setter function type used to pass varios options to
@@ -347,6 +349,17 @@ func (sb *sandbox) setupResolutionFiles() error {
 	return nil
 	return nil
 }
 }
 
 
+func (sb *sandbox) Endpoints() []Endpoint {
+	sb.Lock()
+	defer sb.Unlock()
+
+	endpoints := make([]Endpoint, len(sb.endpoints))
+	for i, ep := range sb.endpoints {
+		endpoints[i] = ep
+	}
+	return endpoints
+}
+
 func (sb *sandbox) getConnectedEndpoints() []*endpoint {
 func (sb *sandbox) getConnectedEndpoints() []*endpoint {
 	sb.Lock()
 	sb.Lock()
 	defer sb.Unlock()
 	defer sb.Unlock()