diff --git a/libnetwork/drivers/bridge/bridge_test.go b/libnetwork/drivers/bridge/bridge_test.go index d53d96deb2..94c3fe6b53 100644 --- a/libnetwork/drivers/bridge/bridge_test.go +++ b/libnetwork/drivers/bridge/bridge_test.go @@ -171,6 +171,14 @@ func TestCreateLinkWithOptions(t *testing.T) { } } +func getExposedPorts() []netutils.TransportPort { + return []netutils.TransportPort{ + netutils.TransportPort{Proto: netutils.TCP, Port: uint16(5000)}, + netutils.TransportPort{Proto: netutils.UDP, Port: uint16(400)}, + netutils.TransportPort{Proto: netutils.TCP, Port: uint16(600)}, + } +} + func getPortMapping() []netutils.PortBinding { return []netutils.PortBinding{ netutils.PortBinding{Proto: netutils.TCP, Port: uint16(230), HostPort: uint16(23000)}, @@ -201,9 +209,9 @@ func TestLinkContainers(t *testing.T) { t.Fatalf("Failed to create bridge: %v", err) } - portMappings := getPortMapping() + exposedPorts := getExposedPorts() epOptions := make(map[string]interface{}) - epOptions[options.PortMap] = portMappings + epOptions[options.ExposedPorts] = exposedPorts sinfo, err := d.CreateEndpoint("net1", "ep1", epOptions) if err != nil { @@ -235,13 +243,12 @@ func TestLinkContainers(t *testing.T) { t.Fatalf("Failed to link ep1 and ep2") } - out, err := iptables.Raw("-L", "DOCKER") - for _, pm := range portMappings { + out, err := iptables.Raw("-L", DockerChain) + for _, pm := range exposedPorts { regex := fmt.Sprintf("%s dpt:%d", pm.Proto.String(), pm.Port) re := regexp.MustCompile(regex) matches := re.FindAllString(string(out[:]), -1) - // There will be 2 matches : Port-Mapping and Linking table rules - if len(matches) < 2 { + if len(matches) != 1 { t.Fatalf("IP Tables programming failed %s", string(out[:])) } @@ -257,13 +264,12 @@ func TestLinkContainers(t *testing.T) { t.Fatalf("Failed to unlink ep1 and ep2") } - out, err = iptables.Raw("-L", "DOCKER") - for _, pm := range portMappings { + out, err = iptables.Raw("-L", DockerChain) + for _, pm := range exposedPorts { regex := fmt.Sprintf("%s dpt:%d", pm.Proto.String(), pm.Port) re := regexp.MustCompile(regex) matches := re.FindAllString(string(out[:]), -1) - // There will be 1 match : Port-Mapping - if len(matches) > 1 { + if len(matches) != 0 { t.Fatalf("Leave should have deleted relevant IPTables rules %s", string(out[:])) } @@ -282,13 +288,12 @@ func TestLinkContainers(t *testing.T) { _, err = d.Join("net1", "ep2", "", genericOption) if err != nil { - out, err = iptables.Raw("-L", "DOCKER") - for _, pm := range portMappings { + out, err = iptables.Raw("-L", DockerChain) + for _, pm := range exposedPorts { regex := fmt.Sprintf("%s dpt:%d", pm.Proto.String(), pm.Port) re := regexp.MustCompile(regex) matches := re.FindAllString(string(out[:]), -1) - // There must be 1 match : Port-Mapping - if len(matches) > 1 { + if len(matches) != 0 { t.Fatalf("Error handling should rollback relevant IPTables rules %s", string(out[:])) } @@ -298,6 +303,8 @@ func TestLinkContainers(t *testing.T) { t.Fatalf("Error handling should rollback relevant IPTables rules %s", string(out[:])) } } + } else { + t.Fatalf("Expected Join to fail given link conditions are not satisfied") } } diff --git a/libnetwork/endpoint.go b/libnetwork/endpoint.go index 605616064a..70dd600ef3 100644 --- a/libnetwork/endpoint.go +++ b/libnetwork/endpoint.go @@ -482,22 +482,27 @@ func JoinOptionUseDefaultSandbox() EndpointOption { } } -// CreateOptionPortMapping function returns an option setter for the container exposed +// CreateOptionExposedPorts function returns an option setter for the container exposed +// ports option to be passed to network.CreateEndpoint() method. +func CreateOptionExposedPorts(exposedPorts []netutils.TransportPort) EndpointOption { + return func(ep *endpoint) { + // Defensive copy + eps := make([]netutils.TransportPort, len(exposedPorts)) + copy(eps, exposedPorts) + // Store endpoint label and in generic because driver needs it + ep.exposedPorts = eps + ep.generic[options.ExposedPorts] = eps + } +} + +// CreateOptionPortMapping function returns an option setter for the mapping // ports option to be passed to network.CreateEndpoint() method. func CreateOptionPortMapping(portBindings []netutils.PortBinding) EndpointOption { return func(ep *endpoint) { - // Extract and store exposed ports as this is the only concern of libnetwork endpoint // Store a copy of the bindings as generic data to pass to the driver - pbs := make([]netutils.PortBinding, 0, len(portBindings)) - exp := make([]netutils.TransportPort, 0, len(portBindings)) - - for _, b := range portBindings { - pbs = append(pbs, b.GetCopy()) - exp = append(exp, netutils.TransportPort{Proto: b.Proto, Port: b.Port}) - } - + pbs := make([]netutils.PortBinding, len(portBindings)) + copy(pbs, portBindings) ep.generic[options.PortMap] = pbs - ep.exposedPorts = exp } } diff --git a/libnetwork/libnetwork_test.go b/libnetwork/libnetwork_test.go index fc51f49c97..6e74952f5d 100644 --- a/libnetwork/libnetwork_test.go +++ b/libnetwork/libnetwork_test.go @@ -179,7 +179,7 @@ func TestBridge(t *testing.T) { t.Fatalf("Unexpected format for port mapping in endpoint operational data") } if len(pm) != 3 { - t.Fatalf("Incomplete data for port mapping in endpoint operational data") + t.Fatalf("Incomplete data for port mapping in endpoint operational data: %d", len(pm)) } if err := ep.Delete(); err != nil { diff --git a/libnetwork/netutils/utils.go b/libnetwork/netutils/utils.go index 05ce372f22..158b2998cf 100644 --- a/libnetwork/netutils/utils.go +++ b/libnetwork/netutils/utils.go @@ -39,6 +39,11 @@ type TransportPort struct { Port uint16 } +// GetCopy returns a copy of this TransportPort structure instance +func (t *TransportPort) GetCopy() TransportPort { + return TransportPort{Proto: t.Proto, Port: t.Port} +} + // PortBinding represent a port binding between the container an the host type PortBinding struct { Proto Protocol