Move network operations out of container package
These network operations really don't have anything to do with the container but rather are setting up the networking. Ideally these wouldn't get shoved into the daemon package, but doing something else (e.g. extract a network service into a new package) but there's a lot more work to do in that regard. In reality, this probably simplifies some of that work as it moves all the network operations to the same place. Signed-off-by: Brian Goff <cpuguy83@gmail.com>
This commit is contained in:
parent
17b039cb49
commit
cc8f358c23
5 changed files with 367 additions and 387 deletions
|
@ -6,11 +6,9 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
|
@ -19,7 +17,6 @@ import (
|
|||
"github.com/containerd/containerd/cio"
|
||||
containertypes "github.com/docker/docker/api/types/container"
|
||||
mounttypes "github.com/docker/docker/api/types/mount"
|
||||
networktypes "github.com/docker/docker/api/types/network"
|
||||
swarmtypes "github.com/docker/docker/api/types/swarm"
|
||||
"github.com/docker/docker/container/stream"
|
||||
"github.com/docker/docker/daemon/exec"
|
||||
|
@ -28,7 +25,6 @@ import (
|
|||
"github.com/docker/docker/daemon/network"
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/layer"
|
||||
"github.com/docker/docker/opts"
|
||||
"github.com/docker/docker/pkg/containerfs"
|
||||
"github.com/docker/docker/pkg/idtools"
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
|
@ -36,15 +32,9 @@ import (
|
|||
"github.com/docker/docker/pkg/symlink"
|
||||
"github.com/docker/docker/pkg/system"
|
||||
"github.com/docker/docker/restartmanager"
|
||||
"github.com/docker/docker/runconfig"
|
||||
"github.com/docker/docker/volume"
|
||||
volumemounts "github.com/docker/docker/volume/mounts"
|
||||
"github.com/docker/go-connections/nat"
|
||||
units "github.com/docker/go-units"
|
||||
"github.com/docker/libnetwork"
|
||||
"github.com/docker/libnetwork/netlabel"
|
||||
"github.com/docker/libnetwork/options"
|
||||
"github.com/docker/libnetwork/types"
|
||||
"github.com/docker/go-units"
|
||||
agentexec "github.com/docker/swarmkit/agent/exec"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
@ -52,11 +42,6 @@ import (
|
|||
|
||||
const configFileName = "config.v2.json"
|
||||
|
||||
var (
|
||||
errInvalidEndpoint = errors.New("invalid endpoint while building port map info")
|
||||
errInvalidNetwork = errors.New("invalid network settings while building port map info")
|
||||
)
|
||||
|
||||
// ExitStatus provides exit reasons for a container.
|
||||
type ExitStatus struct {
|
||||
// The exit code with which the container exited.
|
||||
|
@ -538,366 +523,6 @@ func (container *Container) InitDNSHostConfig() {
|
|||
}
|
||||
}
|
||||
|
||||
// GetEndpointInNetwork returns the container's endpoint to the provided network.
|
||||
func (container *Container) GetEndpointInNetwork(n libnetwork.Network) (libnetwork.Endpoint, error) {
|
||||
endpointName := strings.TrimPrefix(container.Name, "/")
|
||||
return n.EndpointByName(endpointName)
|
||||
}
|
||||
|
||||
func (container *Container) buildPortMapInfo(ep libnetwork.Endpoint) error {
|
||||
if ep == nil {
|
||||
return errInvalidEndpoint
|
||||
}
|
||||
|
||||
networkSettings := container.NetworkSettings
|
||||
if networkSettings == nil {
|
||||
return errInvalidNetwork
|
||||
}
|
||||
|
||||
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()
|
||||
if err != nil {
|
||||
return pm, err
|
||||
}
|
||||
|
||||
if driverInfo == nil {
|
||||
// It is not an error for epInfo to be nil
|
||||
return pm, nil
|
||||
}
|
||||
|
||||
if expData, ok := driverInfo[netlabel.ExposedPorts]; ok {
|
||||
if exposedPorts, ok := expData.([]types.TransportPort); ok {
|
||||
for _, tp := range exposedPorts {
|
||||
natPort, err := nat.NewPort(tp.Proto.String(), strconv.Itoa(int(tp.Port)))
|
||||
if err != nil {
|
||||
return pm, fmt.Errorf("Error parsing Port value(%v):%v", tp.Port, err)
|
||||
}
|
||||
pm[natPort] = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mapData, ok := driverInfo[netlabel.PortMap]
|
||||
if !ok {
|
||||
return pm, nil
|
||||
}
|
||||
|
||||
if portMapping, ok := mapData.([]types.PortBinding); ok {
|
||||
for _, pp := range portMapping {
|
||||
natPort, err := nat.NewPort(pp.Proto.String(), strconv.Itoa(int(pp.Port)))
|
||||
if err != nil {
|
||||
return pm, err
|
||||
}
|
||||
natBndg := nat.PortBinding{HostIP: pp.HostIP.String(), HostPort: strconv.Itoa(int(pp.HostPort))}
|
||||
pm[natPort] = append(pm[natPort], natBndg)
|
||||
}
|
||||
}
|
||||
|
||||
return pm, nil
|
||||
}
|
||||
|
||||
// GetSandboxPortMapInfo retrieves the current port-mapping programmed for the given sandbox
|
||||
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.
|
||||
func (container *Container) BuildEndpointInfo(n libnetwork.Network, ep libnetwork.Endpoint) error {
|
||||
if ep == nil {
|
||||
return errInvalidEndpoint
|
||||
}
|
||||
|
||||
networkSettings := container.NetworkSettings
|
||||
if networkSettings == nil {
|
||||
return errInvalidNetwork
|
||||
}
|
||||
|
||||
epInfo := ep.Info()
|
||||
if epInfo == nil {
|
||||
// It is not an error to get an empty endpoint info
|
||||
return nil
|
||||
}
|
||||
|
||||
if _, ok := networkSettings.Networks[n.Name()]; !ok {
|
||||
networkSettings.Networks[n.Name()] = &network.EndpointSettings{
|
||||
EndpointSettings: &networktypes.EndpointSettings{},
|
||||
}
|
||||
}
|
||||
networkSettings.Networks[n.Name()].NetworkID = n.ID()
|
||||
networkSettings.Networks[n.Name()].EndpointID = ep.ID()
|
||||
|
||||
iface := epInfo.Iface()
|
||||
if iface == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if iface.MacAddress() != nil {
|
||||
networkSettings.Networks[n.Name()].MacAddress = iface.MacAddress().String()
|
||||
}
|
||||
|
||||
if iface.Address() != nil {
|
||||
ones, _ := iface.Address().Mask.Size()
|
||||
networkSettings.Networks[n.Name()].IPAddress = iface.Address().IP.String()
|
||||
networkSettings.Networks[n.Name()].IPPrefixLen = ones
|
||||
}
|
||||
|
||||
if iface.AddressIPv6() != nil && iface.AddressIPv6().IP.To16() != nil {
|
||||
onesv6, _ := iface.AddressIPv6().Mask.Size()
|
||||
networkSettings.Networks[n.Name()].GlobalIPv6Address = iface.AddressIPv6().IP.String()
|
||||
networkSettings.Networks[n.Name()].GlobalIPv6PrefixLen = onesv6
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type named interface {
|
||||
Name() string
|
||||
}
|
||||
|
||||
// UpdateJoinInfo updates network settings when container joins network n with endpoint ep.
|
||||
func (container *Container) UpdateJoinInfo(n named, ep libnetwork.Endpoint) error {
|
||||
if err := container.buildPortMapInfo(ep); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
epInfo := ep.Info()
|
||||
if epInfo == nil {
|
||||
// It is not an error to get an empty endpoint info
|
||||
return nil
|
||||
}
|
||||
if epInfo.Gateway() != nil {
|
||||
container.NetworkSettings.Networks[n.Name()].Gateway = epInfo.Gateway().String()
|
||||
}
|
||||
if epInfo.GatewayIPv6().To16() != nil {
|
||||
container.NetworkSettings.Networks[n.Name()].IPv6Gateway = epInfo.GatewayIPv6().String()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateSandboxNetworkSettings updates the sandbox ID and Key.
|
||||
func (container *Container) UpdateSandboxNetworkSettings(sb libnetwork.Sandbox) error {
|
||||
container.NetworkSettings.SandboxID = sb.ID()
|
||||
container.NetworkSettings.SandboxKey = sb.Key()
|
||||
return nil
|
||||
}
|
||||
|
||||
// BuildJoinOptions builds endpoint Join options from a given network.
|
||||
func (container *Container) BuildJoinOptions(n named) ([]libnetwork.EndpointOption, error) {
|
||||
var joinOptions []libnetwork.EndpointOption
|
||||
if epConfig, ok := container.NetworkSettings.Networks[n.Name()]; ok {
|
||||
for _, str := range epConfig.Links {
|
||||
name, alias, err := opts.ParseLink(str)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
joinOptions = append(joinOptions, libnetwork.CreateOptionAlias(name, alias))
|
||||
}
|
||||
for k, v := range epConfig.DriverOpts {
|
||||
joinOptions = append(joinOptions, libnetwork.EndpointOptionGeneric(options.Generic{k: v}))
|
||||
}
|
||||
}
|
||||
|
||||
return joinOptions, nil
|
||||
}
|
||||
|
||||
// BuildCreateEndpointOptions builds endpoint options from a given network.
|
||||
func (container *Container) BuildCreateEndpointOptions(n libnetwork.Network, epConfig *networktypes.EndpointSettings, sb libnetwork.Sandbox, daemonDNS []string) ([]libnetwork.EndpointOption, error) {
|
||||
var (
|
||||
bindings = make(nat.PortMap)
|
||||
pbList []types.PortBinding
|
||||
exposeList []types.TransportPort
|
||||
createOptions []libnetwork.EndpointOption
|
||||
)
|
||||
|
||||
defaultNetName := runconfig.DefaultDaemonNetworkMode().NetworkName()
|
||||
|
||||
if (!container.EnableServiceDiscoveryOnDefaultNetwork() && n.Name() == defaultNetName) ||
|
||||
container.NetworkSettings.IsAnonymousEndpoint {
|
||||
createOptions = append(createOptions, libnetwork.CreateOptionAnonymous())
|
||||
}
|
||||
|
||||
if epConfig != nil {
|
||||
ipam := epConfig.IPAMConfig
|
||||
|
||||
if ipam != nil {
|
||||
var (
|
||||
ipList []net.IP
|
||||
ip, ip6, linkip net.IP
|
||||
)
|
||||
|
||||
for _, ips := range ipam.LinkLocalIPs {
|
||||
if linkip = net.ParseIP(ips); linkip == nil && ips != "" {
|
||||
return nil, errors.Errorf("Invalid link-local IP address: %s", ipam.LinkLocalIPs)
|
||||
}
|
||||
ipList = append(ipList, linkip)
|
||||
|
||||
}
|
||||
|
||||
if ip = net.ParseIP(ipam.IPv4Address); ip == nil && ipam.IPv4Address != "" {
|
||||
return nil, errors.Errorf("Invalid IPv4 address: %s)", ipam.IPv4Address)
|
||||
}
|
||||
|
||||
if ip6 = net.ParseIP(ipam.IPv6Address); ip6 == nil && ipam.IPv6Address != "" {
|
||||
return nil, errors.Errorf("Invalid IPv6 address: %s)", ipam.IPv6Address)
|
||||
}
|
||||
|
||||
createOptions = append(createOptions,
|
||||
libnetwork.CreateOptionIpam(ip, ip6, ipList, nil))
|
||||
|
||||
}
|
||||
|
||||
for _, alias := range epConfig.Aliases {
|
||||
createOptions = append(createOptions, libnetwork.CreateOptionMyAlias(alias))
|
||||
}
|
||||
for k, v := range epConfig.DriverOpts {
|
||||
createOptions = append(createOptions, libnetwork.EndpointOptionGeneric(options.Generic{k: v}))
|
||||
}
|
||||
}
|
||||
|
||||
if container.NetworkSettings.Service != nil {
|
||||
svcCfg := container.NetworkSettings.Service
|
||||
|
||||
var vip string
|
||||
if svcCfg.VirtualAddresses[n.ID()] != nil {
|
||||
vip = svcCfg.VirtualAddresses[n.ID()].IPv4
|
||||
}
|
||||
|
||||
var portConfigs []*libnetwork.PortConfig
|
||||
for _, portConfig := range svcCfg.ExposedPorts {
|
||||
portConfigs = append(portConfigs, &libnetwork.PortConfig{
|
||||
Name: portConfig.Name,
|
||||
Protocol: libnetwork.PortConfig_Protocol(portConfig.Protocol),
|
||||
TargetPort: portConfig.TargetPort,
|
||||
PublishedPort: portConfig.PublishedPort,
|
||||
})
|
||||
}
|
||||
|
||||
createOptions = append(createOptions, libnetwork.CreateOptionService(svcCfg.Name, svcCfg.ID, net.ParseIP(vip), portConfigs, svcCfg.Aliases[n.ID()]))
|
||||
}
|
||||
|
||||
if !containertypes.NetworkMode(n.Name()).IsUserDefined() {
|
||||
createOptions = append(createOptions, libnetwork.CreateOptionDisableResolution())
|
||||
}
|
||||
|
||||
// configs that are applicable only for the endpoint in the network
|
||||
// to which container was connected to on docker run.
|
||||
// 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() == defaultNetName && 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
|
||||
}
|
||||
|
||||
if container.HostConfig.PortBindings != nil {
|
||||
for p, b := range container.HostConfig.PortBindings {
|
||||
bindings[p] = []nat.PortBinding{}
|
||||
for _, bb := range b {
|
||||
bindings[p] = append(bindings[p], nat.PortBinding{
|
||||
HostIP: bb.HostIP,
|
||||
HostPort: bb.HostPort,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
portSpecs := container.Config.ExposedPorts
|
||||
ports := make([]nat.Port, len(portSpecs))
|
||||
var i int
|
||||
for p := range portSpecs {
|
||||
ports[i] = p
|
||||
i++
|
||||
}
|
||||
nat.SortPortMap(ports, bindings)
|
||||
for _, port := range ports {
|
||||
expose := types.TransportPort{}
|
||||
expose.Proto = types.ParseProtocol(port.Proto())
|
||||
expose.Port = uint16(port.Int())
|
||||
exposeList = append(exposeList, expose)
|
||||
|
||||
pb := types.PortBinding{Port: expose.Port, Proto: expose.Proto}
|
||||
binding := bindings[port]
|
||||
for i := 0; i < len(binding); i++ {
|
||||
pbCopy := pb.GetCopy()
|
||||
newP, err := nat.NewPort(nat.SplitProtoPort(binding[i].HostPort))
|
||||
var portStart, portEnd int
|
||||
if err == nil {
|
||||
portStart, portEnd, err = newP.Range()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "Error parsing HostPort value (%s)", binding[i].HostPort)
|
||||
}
|
||||
pbCopy.HostPort = uint16(portStart)
|
||||
pbCopy.HostPortEnd = uint16(portEnd)
|
||||
pbCopy.HostIP = net.ParseIP(binding[i].HostIP)
|
||||
pbList = append(pbList, pbCopy)
|
||||
}
|
||||
|
||||
if container.HostConfig.PublishAllPorts && len(binding) == 0 {
|
||||
pbList = append(pbList, pb)
|
||||
}
|
||||
}
|
||||
|
||||
var dns []string
|
||||
|
||||
if len(container.HostConfig.DNS) > 0 {
|
||||
dns = container.HostConfig.DNS
|
||||
} else if len(daemonDNS) > 0 {
|
||||
dns = daemonDNS
|
||||
}
|
||||
|
||||
if len(dns) > 0 {
|
||||
createOptions = append(createOptions,
|
||||
libnetwork.CreateOptionDNS(dns))
|
||||
}
|
||||
|
||||
createOptions = append(createOptions,
|
||||
libnetwork.CreateOptionPortMapping(pbList),
|
||||
libnetwork.CreateOptionExposedPorts(exposeList))
|
||||
|
||||
return createOptions, nil
|
||||
}
|
||||
|
||||
// UpdateMonitor updates monitor configure for running container
|
||||
func (container *Container) UpdateMonitor(restartPolicy containertypes.RestartPolicy) {
|
||||
type policySetter interface {
|
||||
|
|
|
@ -31,7 +31,7 @@ var (
|
|||
// ErrRootFSReadOnly is returned when a container
|
||||
// rootfs is marked readonly.
|
||||
ErrRootFSReadOnly = errors.New("container rootfs is marked read-only")
|
||||
getPortMapInfo = container.GetSandboxPortMapInfo
|
||||
getPortMapInfo = getSandboxPortMapInfo
|
||||
)
|
||||
|
||||
func (daemon *Daemon) getDNSSearchSettings(container *container.Container) []string {
|
||||
|
@ -288,7 +288,7 @@ func (daemon *Daemon) updateNetworkSettings(container *container.Container, n li
|
|||
}
|
||||
|
||||
func (daemon *Daemon) updateEndpointNetworkSettings(container *container.Container, n libnetwork.Network, ep libnetwork.Endpoint) error {
|
||||
if err := container.BuildEndpointInfo(n, ep); err != nil {
|
||||
if err := buildEndpointInfo(container.NetworkSettings, n, ep); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -572,7 +572,7 @@ func (daemon *Daemon) allocateNetwork(container *container.Container) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
container.UpdateSandboxNetworkSettings(sb)
|
||||
updateSandboxNetworkSettings(container, sb)
|
||||
defer func() {
|
||||
if err != nil {
|
||||
sb.Delete()
|
||||
|
@ -740,7 +740,7 @@ func (daemon *Daemon) connectToNetwork(container *container.Container, idOrName
|
|||
|
||||
controller := daemon.netController
|
||||
sb := daemon.getNetworkSandbox(container)
|
||||
createOptions, err := container.BuildCreateEndpointOptions(n, endpointConfig, sb, daemon.configStore.DNS)
|
||||
createOptions, err := buildCreateEndpointOptions(container, n, endpointConfig, sb, daemon.configStore.DNS)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -779,10 +779,10 @@ func (daemon *Daemon) connectToNetwork(container *container.Container, idOrName
|
|||
return err
|
||||
}
|
||||
|
||||
container.UpdateSandboxNetworkSettings(sb)
|
||||
updateSandboxNetworkSettings(container, sb)
|
||||
}
|
||||
|
||||
joinOptions, err := container.BuildJoinOptions(n)
|
||||
joinOptions, err := buildJoinOptions(container.NetworkSettings, n)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -798,7 +798,7 @@ func (daemon *Daemon) connectToNetwork(container *container.Container, idOrName
|
|||
}
|
||||
}
|
||||
|
||||
if err := container.UpdateJoinInfo(n, ep); err != nil {
|
||||
if err := updateJoinInfo(container.NetworkSettings, n, ep); err != nil {
|
||||
return fmt.Errorf("Updating join info failed: %v", err)
|
||||
}
|
||||
|
||||
|
@ -809,6 +809,37 @@ func (daemon *Daemon) connectToNetwork(container *container.Container, idOrName
|
|||
return nil
|
||||
}
|
||||
|
||||
func updateJoinInfo(networkSettings *network.Settings, n libnetwork.Network, ep libnetwork.Endpoint) error { // nolint: interfacer
|
||||
if ep == nil {
|
||||
return errors.New("invalid enppoint whhile building portmap info")
|
||||
}
|
||||
|
||||
if networkSettings == nil {
|
||||
return errors.New("invalid network settings while building port map info")
|
||||
}
|
||||
|
||||
if len(networkSettings.Ports) == 0 {
|
||||
pm, err := getEndpointPortMapInfo(ep)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
networkSettings.Ports = pm
|
||||
}
|
||||
|
||||
epInfo := ep.Info()
|
||||
if epInfo == nil {
|
||||
// It is not an error to get an empty endpoint info
|
||||
return nil
|
||||
}
|
||||
if epInfo.Gateway() != nil {
|
||||
networkSettings.Networks[n.Name()].Gateway = epInfo.Gateway().String()
|
||||
}
|
||||
if epInfo.GatewayIPv6().To16() != nil {
|
||||
networkSettings.Networks[n.Name()].IPv6Gateway = epInfo.GatewayIPv6().String()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ForceEndpointDelete deletes an endpoint from a network forcefully
|
||||
func (daemon *Daemon) ForceEndpointDelete(name string, networkName string) error {
|
||||
n, err := daemon.FindNetwork(networkName)
|
||||
|
@ -1110,3 +1141,10 @@ func getNetworkID(name string, endpointSettings *networktypes.EndpointSettings)
|
|||
}
|
||||
return name
|
||||
}
|
||||
|
||||
// updateSandboxNetworkSettings updates the sandbox ID and Key.
|
||||
func updateSandboxNetworkSettings(c *container.Container, sb libnetwork.Sandbox) error {
|
||||
c.NetworkSettings.SandboxID = sb.ID()
|
||||
c.NetworkSettings.SandboxKey = sb.Key()
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -174,7 +174,7 @@ func (daemon *Daemon) initializeNetworkingPaths(container *container.Container,
|
|||
continue
|
||||
}
|
||||
|
||||
ep, err := nc.GetEndpointInNetwork(sn)
|
||||
ep, err := getEndpointInNetwork(nc.Name, sn)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
|
|
@ -6,19 +6,27 @@ import (
|
|||
"net"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
containertypes "github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/network"
|
||||
"github.com/docker/docker/container"
|
||||
clustertypes "github.com/docker/docker/daemon/cluster/provider"
|
||||
internalnetwork "github.com/docker/docker/daemon/network"
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/docker/docker/opts"
|
||||
"github.com/docker/docker/pkg/plugingetter"
|
||||
"github.com/docker/docker/runconfig"
|
||||
"github.com/docker/go-connections/nat"
|
||||
"github.com/docker/libnetwork"
|
||||
lncluster "github.com/docker/libnetwork/cluster"
|
||||
"github.com/docker/libnetwork/driverapi"
|
||||
"github.com/docker/libnetwork/ipamapi"
|
||||
"github.com/docker/libnetwork/netlabel"
|
||||
"github.com/docker/libnetwork/options"
|
||||
networktypes "github.com/docker/libnetwork/types"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
@ -48,7 +56,7 @@ func (daemon *Daemon) NetworkControllerEnabled() bool {
|
|||
func (daemon *Daemon) FindNetwork(term string) (libnetwork.Network, error) {
|
||||
listByFullName := []libnetwork.Network{}
|
||||
listByPartialID := []libnetwork.Network{}
|
||||
for _, nw := range daemon.GetNetworks() {
|
||||
for _, nw := range daemon.getAllNetworks() {
|
||||
if nw.ID() == term {
|
||||
return nw, nil
|
||||
}
|
||||
|
@ -575,7 +583,7 @@ func (daemon *Daemon) GetNetworks() []libnetwork.Network {
|
|||
// clearAttachableNetworks removes the attachable networks
|
||||
// after disconnecting any connected container
|
||||
func (daemon *Daemon) clearAttachableNetworks() {
|
||||
for _, n := range daemon.GetNetworks() {
|
||||
for _, n := range daemon.getAllNetworks() {
|
||||
if !n.Info().Attachable() {
|
||||
continue
|
||||
}
|
||||
|
@ -599,3 +607,312 @@ func (daemon *Daemon) clearAttachableNetworks() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// buildCreateEndpointOptions builds endpoint options from a given network.
|
||||
func buildCreateEndpointOptions(c *container.Container, n libnetwork.Network, epConfig *network.EndpointSettings, sb libnetwork.Sandbox, daemonDNS []string) ([]libnetwork.EndpointOption, error) {
|
||||
var (
|
||||
bindings = make(nat.PortMap)
|
||||
pbList []networktypes.PortBinding
|
||||
exposeList []networktypes.TransportPort
|
||||
createOptions []libnetwork.EndpointOption
|
||||
)
|
||||
|
||||
defaultNetName := runconfig.DefaultDaemonNetworkMode().NetworkName()
|
||||
|
||||
if (!c.EnableServiceDiscoveryOnDefaultNetwork() && n.Name() == defaultNetName) ||
|
||||
c.NetworkSettings.IsAnonymousEndpoint {
|
||||
createOptions = append(createOptions, libnetwork.CreateOptionAnonymous())
|
||||
}
|
||||
|
||||
if epConfig != nil {
|
||||
ipam := epConfig.IPAMConfig
|
||||
|
||||
if ipam != nil {
|
||||
var (
|
||||
ipList []net.IP
|
||||
ip, ip6, linkip net.IP
|
||||
)
|
||||
|
||||
for _, ips := range ipam.LinkLocalIPs {
|
||||
if linkip = net.ParseIP(ips); linkip == nil && ips != "" {
|
||||
return nil, errors.Errorf("Invalid link-local IP address: %s", ipam.LinkLocalIPs)
|
||||
}
|
||||
ipList = append(ipList, linkip)
|
||||
|
||||
}
|
||||
|
||||
if ip = net.ParseIP(ipam.IPv4Address); ip == nil && ipam.IPv4Address != "" {
|
||||
return nil, errors.Errorf("Invalid IPv4 address: %s)", ipam.IPv4Address)
|
||||
}
|
||||
|
||||
if ip6 = net.ParseIP(ipam.IPv6Address); ip6 == nil && ipam.IPv6Address != "" {
|
||||
return nil, errors.Errorf("Invalid IPv6 address: %s)", ipam.IPv6Address)
|
||||
}
|
||||
|
||||
createOptions = append(createOptions,
|
||||
libnetwork.CreateOptionIpam(ip, ip6, ipList, nil))
|
||||
|
||||
}
|
||||
|
||||
for _, alias := range epConfig.Aliases {
|
||||
createOptions = append(createOptions, libnetwork.CreateOptionMyAlias(alias))
|
||||
}
|
||||
for k, v := range epConfig.DriverOpts {
|
||||
createOptions = append(createOptions, libnetwork.EndpointOptionGeneric(options.Generic{k: v}))
|
||||
}
|
||||
}
|
||||
|
||||
if c.NetworkSettings.Service != nil {
|
||||
svcCfg := c.NetworkSettings.Service
|
||||
|
||||
var vip string
|
||||
if svcCfg.VirtualAddresses[n.ID()] != nil {
|
||||
vip = svcCfg.VirtualAddresses[n.ID()].IPv4
|
||||
}
|
||||
|
||||
var portConfigs []*libnetwork.PortConfig
|
||||
for _, portConfig := range svcCfg.ExposedPorts {
|
||||
portConfigs = append(portConfigs, &libnetwork.PortConfig{
|
||||
Name: portConfig.Name,
|
||||
Protocol: libnetwork.PortConfig_Protocol(portConfig.Protocol),
|
||||
TargetPort: portConfig.TargetPort,
|
||||
PublishedPort: portConfig.PublishedPort,
|
||||
})
|
||||
}
|
||||
|
||||
createOptions = append(createOptions, libnetwork.CreateOptionService(svcCfg.Name, svcCfg.ID, net.ParseIP(vip), portConfigs, svcCfg.Aliases[n.ID()]))
|
||||
}
|
||||
|
||||
if !containertypes.NetworkMode(n.Name()).IsUserDefined() {
|
||||
createOptions = append(createOptions, libnetwork.CreateOptionDisableResolution())
|
||||
}
|
||||
|
||||
// configs that are applicable only for the endpoint in the network
|
||||
// to which container was connected to on docker run.
|
||||
// Ideally all these network-specific endpoint configurations must be moved under
|
||||
// container.NetworkSettings.Networks[n.Name()]
|
||||
if n.Name() == c.HostConfig.NetworkMode.NetworkName() ||
|
||||
(n.Name() == defaultNetName && c.HostConfig.NetworkMode.IsDefault()) {
|
||||
if c.Config.MacAddress != "" {
|
||||
mac, err := net.ParseMAC(c.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
|
||||
}
|
||||
|
||||
if c.HostConfig.PortBindings != nil {
|
||||
for p, b := range c.HostConfig.PortBindings {
|
||||
bindings[p] = []nat.PortBinding{}
|
||||
for _, bb := range b {
|
||||
bindings[p] = append(bindings[p], nat.PortBinding{
|
||||
HostIP: bb.HostIP,
|
||||
HostPort: bb.HostPort,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
portSpecs := c.Config.ExposedPorts
|
||||
ports := make([]nat.Port, len(portSpecs))
|
||||
var i int
|
||||
for p := range portSpecs {
|
||||
ports[i] = p
|
||||
i++
|
||||
}
|
||||
nat.SortPortMap(ports, bindings)
|
||||
for _, port := range ports {
|
||||
expose := networktypes.TransportPort{}
|
||||
expose.Proto = networktypes.ParseProtocol(port.Proto())
|
||||
expose.Port = uint16(port.Int())
|
||||
exposeList = append(exposeList, expose)
|
||||
|
||||
pb := networktypes.PortBinding{Port: expose.Port, Proto: expose.Proto}
|
||||
binding := bindings[port]
|
||||
for i := 0; i < len(binding); i++ {
|
||||
pbCopy := pb.GetCopy()
|
||||
newP, err := nat.NewPort(nat.SplitProtoPort(binding[i].HostPort))
|
||||
var portStart, portEnd int
|
||||
if err == nil {
|
||||
portStart, portEnd, err = newP.Range()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "Error parsing HostPort value (%s)", binding[i].HostPort)
|
||||
}
|
||||
pbCopy.HostPort = uint16(portStart)
|
||||
pbCopy.HostPortEnd = uint16(portEnd)
|
||||
pbCopy.HostIP = net.ParseIP(binding[i].HostIP)
|
||||
pbList = append(pbList, pbCopy)
|
||||
}
|
||||
|
||||
if c.HostConfig.PublishAllPorts && len(binding) == 0 {
|
||||
pbList = append(pbList, pb)
|
||||
}
|
||||
}
|
||||
|
||||
var dns []string
|
||||
|
||||
if len(c.HostConfig.DNS) > 0 {
|
||||
dns = c.HostConfig.DNS
|
||||
} else if len(daemonDNS) > 0 {
|
||||
dns = daemonDNS
|
||||
}
|
||||
|
||||
if len(dns) > 0 {
|
||||
createOptions = append(createOptions,
|
||||
libnetwork.CreateOptionDNS(dns))
|
||||
}
|
||||
|
||||
createOptions = append(createOptions,
|
||||
libnetwork.CreateOptionPortMapping(pbList),
|
||||
libnetwork.CreateOptionExposedPorts(exposeList))
|
||||
|
||||
return createOptions, nil
|
||||
}
|
||||
|
||||
// getEndpointInNetwork returns the container's endpoint to the provided network.
|
||||
func getEndpointInNetwork(name string, n libnetwork.Network) (libnetwork.Endpoint, error) {
|
||||
endpointName := strings.TrimPrefix(name, "/")
|
||||
return n.EndpointByName(endpointName)
|
||||
}
|
||||
|
||||
// getSandboxPortMapInfo retrieves the current port-mapping programmed for the given sandbox
|
||||
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
|
||||
}
|
||||
|
||||
func getEndpointPortMapInfo(ep libnetwork.Endpoint) (nat.PortMap, error) {
|
||||
pm := nat.PortMap{}
|
||||
driverInfo, err := ep.DriverInfo()
|
||||
if err != nil {
|
||||
return pm, err
|
||||
}
|
||||
|
||||
if driverInfo == nil {
|
||||
// It is not an error for epInfo to be nil
|
||||
return pm, nil
|
||||
}
|
||||
|
||||
if expData, ok := driverInfo[netlabel.ExposedPorts]; ok {
|
||||
if exposedPorts, ok := expData.([]networktypes.TransportPort); ok {
|
||||
for _, tp := range exposedPorts {
|
||||
natPort, err := nat.NewPort(tp.Proto.String(), strconv.Itoa(int(tp.Port)))
|
||||
if err != nil {
|
||||
return pm, fmt.Errorf("Error parsing Port value(%v):%v", tp.Port, err)
|
||||
}
|
||||
pm[natPort] = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mapData, ok := driverInfo[netlabel.PortMap]
|
||||
if !ok {
|
||||
return pm, nil
|
||||
}
|
||||
|
||||
if portMapping, ok := mapData.([]networktypes.PortBinding); ok {
|
||||
for _, pp := range portMapping {
|
||||
natPort, err := nat.NewPort(pp.Proto.String(), strconv.Itoa(int(pp.Port)))
|
||||
if err != nil {
|
||||
return pm, err
|
||||
}
|
||||
natBndg := nat.PortBinding{HostIP: pp.HostIP.String(), HostPort: strconv.Itoa(int(pp.HostPort))}
|
||||
pm[natPort] = append(pm[natPort], natBndg)
|
||||
}
|
||||
}
|
||||
|
||||
return pm, nil
|
||||
}
|
||||
|
||||
// buildEndpointInfo sets endpoint-related fields on container.NetworkSettings based on the provided network and endpoint.
|
||||
func buildEndpointInfo(networkSettings *internalnetwork.Settings, n libnetwork.Network, ep libnetwork.Endpoint) error {
|
||||
if ep == nil {
|
||||
return errors.New("endpoint cannot be nil")
|
||||
}
|
||||
|
||||
if networkSettings == nil {
|
||||
return errors.New("network cannot be nil")
|
||||
}
|
||||
|
||||
epInfo := ep.Info()
|
||||
if epInfo == nil {
|
||||
// It is not an error to get an empty endpoint info
|
||||
return nil
|
||||
}
|
||||
|
||||
if _, ok := networkSettings.Networks[n.Name()]; !ok {
|
||||
networkSettings.Networks[n.Name()] = &internalnetwork.EndpointSettings{
|
||||
EndpointSettings: &network.EndpointSettings{},
|
||||
}
|
||||
}
|
||||
networkSettings.Networks[n.Name()].NetworkID = n.ID()
|
||||
networkSettings.Networks[n.Name()].EndpointID = ep.ID()
|
||||
|
||||
iface := epInfo.Iface()
|
||||
if iface == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if iface.MacAddress() != nil {
|
||||
networkSettings.Networks[n.Name()].MacAddress = iface.MacAddress().String()
|
||||
}
|
||||
|
||||
if iface.Address() != nil {
|
||||
ones, _ := iface.Address().Mask.Size()
|
||||
networkSettings.Networks[n.Name()].IPAddress = iface.Address().IP.String()
|
||||
networkSettings.Networks[n.Name()].IPPrefixLen = ones
|
||||
}
|
||||
|
||||
if iface.AddressIPv6() != nil && iface.AddressIPv6().IP.To16() != nil {
|
||||
onesv6, _ := iface.AddressIPv6().Mask.Size()
|
||||
networkSettings.Networks[n.Name()].GlobalIPv6Address = iface.AddressIPv6().IP.String()
|
||||
networkSettings.Networks[n.Name()].GlobalIPv6PrefixLen = onesv6
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// buildJoinOptions builds endpoint Join options from a given network.
|
||||
func buildJoinOptions(networkSettings *internalnetwork.Settings, n interface {
|
||||
Name() string
|
||||
}) ([]libnetwork.EndpointOption, error) {
|
||||
var joinOptions []libnetwork.EndpointOption
|
||||
if epConfig, ok := networkSettings.Networks[n.Name()]; ok {
|
||||
for _, str := range epConfig.Links {
|
||||
name, alias, err := opts.ParseLink(str)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
joinOptions = append(joinOptions, libnetwork.CreateOptionAlias(name, alias))
|
||||
}
|
||||
for k, v := range epConfig.DriverOpts {
|
||||
joinOptions = append(joinOptions, libnetwork.EndpointOptionGeneric(options.Generic{k: v}))
|
||||
}
|
||||
}
|
||||
|
||||
return joinOptions, nil
|
||||
}
|
||||
|
|
|
@ -156,7 +156,7 @@ func (daemon *Daemon) createSpec(c *container.Container) (*specs.Spec, error) {
|
|||
continue
|
||||
}
|
||||
|
||||
ep, err := c.GetEndpointInNetwork(sn)
|
||||
ep, err := getEndpointInNetwork(c.Name, sn)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue