Repository: moby/moby
File: daemon/server/router/container/container_routes.go (Go)

Code before:
	version string,
	nwMode container.NetworkMode,
	netConfig *network.NetworkingConfig,
) (*network.EndpointSettings, error) {
	nwName := nwMode.NetworkName()

	// It's always safe to create an EndpointsConfig entry under nwName if there are
	// no entries already (because there can't be an entry for this network nwName
	// refers to under any other name/short-id/id).
	if len(netConfig.EndpointsConfig) == 0 {
		es := &network.EndpointSettings{}
		netConfig.EndpointsConfig = map[string]*network.EndpointSettings{
			nwName: es,
		}
		return es, nil
	}

	// There cannot be more than one entry in EndpointsConfig with API < 1.44.
	if versions.LessThan(version, "1.44") {
		// No need to check for a match between NetworkMode and the names/ids in EndpointsConfig,
		// the old version of the API would pick this network anyway.
		for _, ep := range netConfig.EndpointsConfig {
			return ep, nil
		}
	}

	// There is existing endpoint config - if it's not indexed by NetworkMode.Name(), we
	// can't tell which network the container-wide settings are intended for. NetworkMode,
	// the keys in EndpointsConfig and the NetworkID in EndpointsConfig may mix network
	// name/id/short-id. It's not safe to create EndpointsConfig under the NetworkMode
	// name to store the container-wide setting, because that may result in two sets
	// of EndpointsConfig for the same network and one set will be discarded later. So,
	// reject the request ...
	ep, ok := netConfig.EndpointsConfig[nwName]
	if !ok {
		return nil, errdefs.InvalidParameter(
			errors.New("HostConfig.NetworkMode must match the identity of a network in NetworkSettings.Networks"))
	}

	return ep, nil
}

func (c *containerRouter) deleteContainers(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
	if err := httputils.ParseForm(r); err != nil {
		return err
	}

	name := vars["name"]
	config := &backend.ContainerRmConfig{
		ForceRemove:  httputils.BoolValue(r, "force"),
		RemoveVolume: httputils.BoolValue(r, "v"),

Review comment (suggestion):
If multiple port bindings trigger the warning, why only list the last one iterated upon?
```go
for ... {
        if versions.Equal(version, "1.52") {
                warningPorts = append(warningPorts, portProto)
        }
}
if len(warningPorts) > 0 {
        return fmt.Sprintf("One or more container ports has an empty list of port-bindings. Starting with API 1.53, the bindings for %s will be discarded.", strings.Join(warningPorts, ", "))
}
return ""
```

Code after:
//
// Preserve this behavior for older API versions but emit a warning for API
// v1.52 and drop that behavior for newer API versions.
//
// See https://github.com/moby/moby/pull/50710#discussion_r2315840899 for more
// context.
func handlePortBindingsBC(hostConfig *container.HostConfig, version string) string {
	var warning string

	for portProto, bindings := range hostConfig.PortBindings {
		if len(bindings) > 0 {
			continue
		}
		if versions.GreaterThan(version, "1.52") && len(bindings) == 0 {
			// Starting with API 1.53, no backfilling is done. An empty slice
			// of port bindings is treated as "no port bindings" by the daemon,
			// but it still needs to backfill empty slices when loading the
			// on-disk state for containers created by older versions of the
			// Engine. Drop the PortBindings entry to ensure that no backfilling
			// will happen when restarting the daemon.
			delete(hostConfig.PortBindings, portProto)
			continue
		}

		if versions.Equal(version, "1.52") {
			warning = fmt.Sprintf("Container port %s has an empty list of port-bindings. Starting with API 1.53, this will be discarded.", portProto)
		}

		hostConfig.PortBindings[portProto] = []nat.PortBinding{{}}
	}

	return warning
}

// epConfigForNetMode finds, or creates, an entry in netConfig.EndpointsConfig
// corresponding to nwMode.
//
// nwMode.NetworkName() may be the network's name, its id, or its short-id.
//
// The corresponding endpoint in netConfig.EndpointsConfig may be keyed on a
// different one of name/id/short-id. If there's any ambiguity (there are
// endpoints but the names don't match), return an error and do not create a new
// endpoint, because it might be a duplicate.
func epConfigForNetMode(
	version string,
	nwMode container.NetworkMode,
	netConfig *network.NetworkingConfig,
) (*network.EndpointSettings, error) {
	nwName := nwMode.NetworkName()

	// It's always safe to create an EndpointsConfig entry under nwName if there are