mirror of
https://github.com/moby/moby.git
synced 2026-01-11 18:51:37 +00:00
daemon: return port-mappings from all endpoints
With improved IPv6 support, a dual-stack container can map a port using two different networks -- one IPv4-only, the other IPv6-only. The daemon was updating containers' `EndpointSettings.Ports` by looking for the first network providing port-mappings. This was incorrect. Instead, iterate over the whole list of endpoints, and merge everything together. The function doing that, ie. `getEndpointPortMapInfo`, is also considered exposed ports, and nil the PortMap entry if an exposed port is found. However, exposed ports are always set on a bridge network, so this was erasing port-mappings found for other networks. Signed-off-by: Albin Kerouanton <albinker@gmail.com>
This commit is contained in:
@@ -1005,24 +1005,16 @@ func getPortMapInfo(sb *libnetwork.Sandbox) nat.PortMap {
|
||||
}
|
||||
|
||||
for _, ep := range sb.Endpoints() {
|
||||
pm = getEndpointPortMapInfo(ep)
|
||||
if len(pm) > 0 {
|
||||
break
|
||||
}
|
||||
getEndpointPortMapInfo(pm, ep)
|
||||
}
|
||||
return pm
|
||||
}
|
||||
|
||||
func getEndpointPortMapInfo(ep *libnetwork.Endpoint) nat.PortMap {
|
||||
pm := nat.PortMap{}
|
||||
driverInfo, err := ep.DriverInfo()
|
||||
if err != nil {
|
||||
return pm
|
||||
}
|
||||
|
||||
func getEndpointPortMapInfo(pm nat.PortMap, ep *libnetwork.Endpoint) {
|
||||
driverInfo, _ := ep.DriverInfo()
|
||||
if driverInfo == nil {
|
||||
// It is not an error for epInfo to be nil
|
||||
return pm
|
||||
return
|
||||
}
|
||||
|
||||
if expData, ok := driverInfo[netlabel.ExposedPorts]; ok {
|
||||
@@ -1033,14 +1025,16 @@ func getEndpointPortMapInfo(ep *libnetwork.Endpoint) nat.PortMap {
|
||||
log.G(context.TODO()).Errorf("invalid exposed port %s: %v", tp.String(), err)
|
||||
continue
|
||||
}
|
||||
pm[natPort] = nil
|
||||
if _, ok := pm[natPort]; !ok {
|
||||
pm[natPort] = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mapData, ok := driverInfo[netlabel.PortMap]
|
||||
if !ok {
|
||||
return pm
|
||||
return
|
||||
}
|
||||
|
||||
if portMapping, ok := mapData.([]lntypes.PortBinding); ok {
|
||||
@@ -1059,8 +1053,6 @@ func getEndpointPortMapInfo(ep *libnetwork.Endpoint) nat.PortMap {
|
||||
pm[natPort] = append(pm[natPort], natBndg)
|
||||
}
|
||||
}
|
||||
|
||||
return pm
|
||||
}
|
||||
|
||||
// buildEndpointInfo sets endpoint-related fields on container.NetworkSettings based on the provided network and endpoint.
|
||||
|
||||
@@ -454,3 +454,42 @@ func TestPublishedPortAlreadyInUse(t *testing.T) {
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(inspect.State.Status, "created"))
|
||||
}
|
||||
|
||||
// TestAllPortMappingsAreReturned check that dual-stack ports mapped through
|
||||
// different networks are correctly reported as dual-stakc.
|
||||
//
|
||||
// Regression test for https://github.com/moby/moby/issues/49654.
|
||||
func TestAllPortMappingsAreReturned(t *testing.T) {
|
||||
ctx := setupTest(t)
|
||||
|
||||
d := daemon.New(t)
|
||||
d.StartWithBusybox(ctx, t, "--userland-proxy=false")
|
||||
defer d.Stop(t)
|
||||
|
||||
apiClient := d.NewClientT(t)
|
||||
defer apiClient.Close()
|
||||
|
||||
nwV4 := network.CreateNoError(ctx, t, apiClient, "testnetv4")
|
||||
defer network.RemoveNoError(ctx, t, apiClient, nwV4)
|
||||
|
||||
nwV6 := network.CreateNoError(ctx, t, apiClient, "testnetv6",
|
||||
network.WithIPv4(false),
|
||||
network.WithIPv6())
|
||||
defer network.RemoveNoError(ctx, t, apiClient, nwV6)
|
||||
|
||||
ctrID := ctr.Run(ctx, t, apiClient,
|
||||
ctr.WithExposedPorts("80/tcp", "81/tcp"),
|
||||
ctr.WithPortMap(nat.PortMap{"80/tcp": {{HostPort: "8000"}}}),
|
||||
ctr.WithEndpointSettings("testnetv4", &networktypes.EndpointSettings{}),
|
||||
ctr.WithEndpointSettings("testnetv6", &networktypes.EndpointSettings{}))
|
||||
defer ctr.Remove(ctx, t, apiClient, ctrID, containertypes.RemoveOptions{Force: true})
|
||||
|
||||
inspect := ctr.Inspect(ctx, t, apiClient, ctrID)
|
||||
assert.DeepEqual(t, inspect.NetworkSettings.Ports, nat.PortMap{
|
||||
"80/tcp": []nat.PortBinding{
|
||||
{HostIP: "0.0.0.0", HostPort: "8000"},
|
||||
{HostIP: "::", HostPort: "8000"},
|
||||
},
|
||||
"81/tcp": nil,
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user