4f0d95fa |
package daemon // import "github.com/docker/docker/daemon" |
2ab94e11 |
import ( |
7d62e40f |
"context" |
cc6aece1 |
"fmt"
"net" |
7ca635a1 |
"sort" |
cc8f358c |
"strconv" |
2ab94e11 |
"strings" |
d59d19c3 |
"sync" |
2ab94e11 |
|
91e197d6 |
"github.com/docker/docker/api/types" |
cc8f358c |
containertypes "github.com/docker/docker/api/types/container" |
c0bc14e8 |
"github.com/docker/docker/api/types/filters" |
91e197d6 |
"github.com/docker/docker/api/types/network" |
cc8f358c |
"github.com/docker/docker/container" |
534a90a9 |
clustertypes "github.com/docker/docker/daemon/cluster/provider" |
cc8f358c |
internalnetwork "github.com/docker/docker/daemon/network" |
d453fe35 |
"github.com/docker/docker/errdefs" |
cc8f358c |
"github.com/docker/docker/opts" |
fc2c0e62 |
"github.com/docker/docker/pkg/plugingetter" |
f15af1ef |
"github.com/docker/docker/runconfig" |
cc8f358c |
"github.com/docker/go-connections/nat" |
2ab94e11 |
"github.com/docker/libnetwork" |
e2ec0067 |
lncluster "github.com/docker/libnetwork/cluster" |
fc2c0e62 |
"github.com/docker/libnetwork/driverapi"
"github.com/docker/libnetwork/ipamapi" |
cc8f358c |
"github.com/docker/libnetwork/netlabel" |
c0bc14e8 |
"github.com/docker/libnetwork/networkdb" |
cc8f358c |
"github.com/docker/libnetwork/options" |
534a90a9 |
networktypes "github.com/docker/libnetwork/types" |
934328d8 |
"github.com/pkg/errors" |
1009e6a4 |
"github.com/sirupsen/logrus" |
2ab94e11 |
)
|
7cf8b207 |
// PredefinedNetworkError is returned when user tries to create predefined network that already exists.
type PredefinedNetworkError string
func (pnr PredefinedNetworkError) Error() string {
return fmt.Sprintf("operation is not permitted on predefined %s network ", string(pnr))
}
// Forbidden denotes the type of this error
func (pnr PredefinedNetworkError) Forbidden() {}
|
eb982e7c |
// NetworkControllerEnabled checks if the networking stack is enabled. |
927b334e |
// This feature depends on OS primitives and it's disabled in systems like Windows. |
eb982e7c |
func (daemon *Daemon) NetworkControllerEnabled() bool {
return daemon.netController != nil
}
|
d6424a08 |
// NetworkController returns the network controller created by the daemon.
func (daemon *Daemon) NetworkController() libnetwork.NetworkController {
return daemon.netController
}
|
ccc2ed01 |
// FindNetwork returns a network based on: |
cafed80c |
// 1. Full ID
// 2. Full Name
// 3. Partial ID
// as long as there is no ambiguity |
ccc2ed01 |
func (daemon *Daemon) FindNetwork(term string) (libnetwork.Network, error) { |
cafed80c |
listByFullName := []libnetwork.Network{}
listByPartialID := []libnetwork.Network{} |
cc8f358c |
for _, nw := range daemon.getAllNetworks() { |
cafed80c |
if nw.ID() == term {
return nw, nil
}
if nw.Name() == term {
listByFullName = append(listByFullName, nw)
}
if strings.HasPrefix(nw.ID(), term) {
listByPartialID = append(listByPartialID, nw)
} |
e52001c5 |
} |
cafed80c |
switch {
case len(listByFullName) == 1:
return listByFullName[0], nil
case len(listByFullName) > 1: |
87a12421 |
return nil, errdefs.InvalidParameter(errors.Errorf("network %s is ambiguous (%d matches found on name)", term, len(listByFullName))) |
cafed80c |
case len(listByPartialID) == 1:
return listByPartialID[0], nil
case len(listByPartialID) > 1: |
87a12421 |
return nil, errdefs.InvalidParameter(errors.Errorf("network %s is ambiguous (%d matches found based on ID prefix)", term, len(listByPartialID))) |
cafed80c |
} |
87a12421 |
// Be very careful to change the error type here, the
// libnetwork.ErrNoSuchNetwork error is used by the controller
// to retry the creation of the network as managed through the swarm manager
return nil, errdefs.NotFound(libnetwork.ErrNoSuchNetwork(term)) |
2ab94e11 |
}
|
e52001c5 |
// GetNetworkByID function returns a network whose ID matches the given ID.
// It fails with an error if no matching network is found.
func (daemon *Daemon) GetNetworkByID(id string) (libnetwork.Network, error) {
c := daemon.netController
if c == nil { |
c0bc14e8 |
return nil, errors.Wrap(libnetwork.ErrNoSuchNetwork(id), "netcontroller is nil") |
dd93571c |
} |
e52001c5 |
return c.NetworkByID(id) |
dd93571c |
} |
2ab94e11 |
|
dd93571c |
// GetNetworkByName function returns a network for a given network name. |
6ad4bf0a |
// If no network name is given, the default network is returned. |
dd93571c |
func (daemon *Daemon) GetNetworkByName(name string) (libnetwork.Network, error) {
c := daemon.netController |
ecffb6d5 |
if c == nil {
return nil, libnetwork.ErrNoSuchNetwork(name)
} |
dd93571c |
if name == "" {
name = c.Config().Daemon.DefaultNetwork |
2ab94e11 |
} |
dd93571c |
return c.NetworkByName(name) |
2ab94e11 |
}
|
e52001c5 |
// GetNetworksByIDPrefix returns a list of networks whose ID partially matches zero or more networks
func (daemon *Daemon) GetNetworksByIDPrefix(partialID string) []libnetwork.Network { |
2ab94e11 |
c := daemon.netController |
ecffb6d5 |
if c == nil {
return nil
} |
2ab94e11 |
list := []libnetwork.Network{}
l := func(nw libnetwork.Network) bool {
if strings.HasPrefix(nw.ID(), partialID) {
list = append(list, nw)
}
return false
}
c.WalkNetworks(l)
return list
}
|
3ca29823 |
// getAllNetworks returns a list containing all networks
func (daemon *Daemon) getAllNetworks() []libnetwork.Network { |
b249ccb1 |
c := daemon.netController
if c == nil {
return nil
}
return c.Networks() |
26dd026b |
}
|
d59d19c3 |
type ingressJob struct { |
6f4bb796 |
create *clustertypes.NetworkCreateRequest
ip net.IP
jobDone chan struct{} |
534a90a9 |
}
|
d59d19c3 |
var (
ingressWorkerOnce sync.Once
ingressJobsChannel chan *ingressJob
ingressID string
)
func (daemon *Daemon) startIngressWorker() {
ingressJobsChannel = make(chan *ingressJob, 100)
go func() { |
f7f101d5 |
// nolint: gosimple |
d59d19c3 |
for {
select {
case r := <-ingressJobsChannel:
if r.create != nil {
daemon.setupIngress(r.create, r.ip, ingressID)
ingressID = r.create.ID
} else {
daemon.releaseIngress(ingressID)
ingressID = ""
} |
6f4bb796 |
close(r.jobDone) |
d59d19c3 |
}
}
}()
} |
534a90a9 |
|
d59d19c3 |
// enqueueIngressJob adds a ingress add/rm request to the worker queue.
// It guarantees the worker is started.
func (daemon *Daemon) enqueueIngressJob(job *ingressJob) {
ingressWorkerOnce.Do(daemon.startIngressWorker)
ingressJobsChannel <- job |
534a90a9 |
}
// SetupIngress setups ingress networking. |
6f4bb796 |
// The function returns a channel which will signal the caller when the programming is completed.
func (daemon *Daemon) SetupIngress(create clustertypes.NetworkCreateRequest, nodeIP string) (<-chan struct{}, error) { |
534a90a9 |
ip, _, err := net.ParseCIDR(nodeIP)
if err != nil { |
6f4bb796 |
return nil, err |
534a90a9 |
} |
6f4bb796 |
done := make(chan struct{})
daemon.enqueueIngressJob(&ingressJob{&create, ip, done})
return done, nil |
d59d19c3 |
} |
534a90a9 |
|
d59d19c3 |
// ReleaseIngress releases the ingress networking. |
6f4bb796 |
// The function returns a channel which will signal the caller when the programming is completed.
func (daemon *Daemon) ReleaseIngress() (<-chan struct{}, error) {
done := make(chan struct{})
daemon.enqueueIngressJob(&ingressJob{nil, nil, done})
return done, nil |
d59d19c3 |
} |
534a90a9 |
|
d59d19c3 |
func (daemon *Daemon) setupIngress(create *clustertypes.NetworkCreateRequest, ip net.IP, staleID string) {
controller := daemon.netController
controller.AgentInitWait() |
534a90a9 |
|
d59d19c3 |
if staleID != "" && staleID != create.ID {
daemon.releaseIngress(staleID)
} |
a4926a4d |
|
d59d19c3 |
if _, err := daemon.createNetwork(create.NetworkCreateRequest, create.ID, true); err != nil {
// If it is any other error other than already
// exists error log error and return.
if _, ok := err.(libnetwork.NetworkNameError); !ok {
logrus.Errorf("Failed creating ingress network: %v", err)
return |
534a90a9 |
} |
d59d19c3 |
// Otherwise continue down the call to create or recreate sandbox.
} |
534a90a9 |
|
41071d66 |
_, err := daemon.GetNetworkByID(create.ID) |
d59d19c3 |
if err != nil {
logrus.Errorf("Failed getting ingress network by id after creating: %v", err)
}
} |
534a90a9 |
|
d59d19c3 |
func (daemon *Daemon) releaseIngress(id string) {
controller := daemon.netController
if id == "" {
return
}
n, err := controller.NetworkByID(id)
if err != nil {
logrus.Errorf("failed to retrieve ingress network %s: %v", id, err)
return
}
|
8e0f6bc9 |
if err := n.Delete(libnetwork.NetworkDeleteOptionRemoveLB); err != nil { |
d59d19c3 |
logrus.Errorf("Failed to delete ingress network %s: %v", n.ID(), err)
return
} |
534a90a9 |
}
// SetNetworkBootstrapKeys sets the bootstrap keys.
func (daemon *Daemon) SetNetworkBootstrapKeys(keys []*networktypes.EncryptionKey) error { |
e2ec0067 |
err := daemon.netController.SetKeys(keys)
if err == nil {
// Upon successful key setting dispatch the keys available event
daemon.cluster.SendClusterEvent(lncluster.EventNetworkKeysAvailable)
}
return err |
534a90a9 |
}
|
99a98ccc |
// UpdateAttachment notifies the attacher about the attachment config.
func (daemon *Daemon) UpdateAttachment(networkName, networkID, containerID string, config *network.NetworkingConfig) error {
if daemon.clusterProvider == nil {
return fmt.Errorf("cluster provider is not initialized")
}
if err := daemon.clusterProvider.UpdateAttachment(networkName, containerID, config); err != nil {
return daemon.clusterProvider.UpdateAttachment(networkID, containerID, config)
}
return nil
}
// WaitForDetachment makes the cluster manager wait for detachment of
// the container from the network.
func (daemon *Daemon) WaitForDetachment(ctx context.Context, networkName, networkID, taskID, containerID string) error {
if daemon.clusterProvider == nil {
return fmt.Errorf("cluster provider is not initialized")
}
return daemon.clusterProvider.WaitForDetachment(ctx, networkName, networkID, taskID, containerID)
}
|
534a90a9 |
// CreateManagedNetwork creates an agent network.
func (daemon *Daemon) CreateManagedNetwork(create clustertypes.NetworkCreateRequest) error {
_, err := daemon.createNetwork(create.NetworkCreateRequest, create.ID, true)
return err
}
|
2ab94e11 |
// CreateNetwork creates a network with the given name, driver and other optional parameters |
b9c94b70 |
func (daemon *Daemon) CreateNetwork(create types.NetworkCreateRequest) (*types.NetworkCreateResponse, error) { |
534a90a9 |
resp, err := daemon.createNetwork(create, "", false)
if err != nil {
return nil, err
}
return resp, err
}
func (daemon *Daemon) createNetwork(create types.NetworkCreateRequest, id string, agent bool) (*types.NetworkCreateResponse, error) { |
7cf8b207 |
if runconfig.IsPreDefinedNetwork(create.Name) {
return nil, PredefinedNetworkError(create.Name) |
3ca29823 |
}
var warning string
nw, err := daemon.GetNetworkByName(create.Name)
if err != nil {
if _, ok := err.(libnetwork.ErrNoSuchNetwork); !ok {
return nil, err
}
}
if nw != nil { |
94b880f9 |
// check if user defined CheckDuplicate, if set true, return err
// otherwise prepare a warning message |
3ca29823 |
if create.CheckDuplicate { |
cafed80c |
if !agent || nw.Info().Dynamic() {
return nil, libnetwork.NetworkNameError(create.Name)
} |
3ca29823 |
}
warning = fmt.Sprintf("Network with name %s (id : %s) already exists", nw.Name(), nw.ID())
}
|
2ab94e11 |
c := daemon.netController |
3ca29823 |
driver := create.Driver |
2ab94e11 |
if driver == "" {
driver = c.Config().Daemon.DefaultDriver
}
|
fc214b44 |
nwOptions := []libnetwork.NetworkOption{ |
3ca29823 |
libnetwork.NetworkOptionEnableIPv6(create.EnableIPv6),
libnetwork.NetworkOptionDriverOpts(create.Options),
libnetwork.NetworkOptionLabels(create.Labels), |
abcb699a |
libnetwork.NetworkOptionAttachable(create.Attachable), |
d59d19c3 |
libnetwork.NetworkOptionIngress(create.Ingress), |
fcafc710 |
libnetwork.NetworkOptionScope(create.Scope), |
fc214b44 |
} |
8f7a8c75 |
|
9ee7b4dd |
if create.ConfigOnly {
nwOptions = append(nwOptions, libnetwork.NetworkOptionConfigOnly())
}
|
8f7a8c75 |
if create.IPAM != nil {
ipam := create.IPAM
v4Conf, v6Conf, err := getIpamConfig(ipam.Config)
if err != nil {
return nil, err
}
nwOptions = append(nwOptions, libnetwork.NetworkOptionIpam(ipam.Driver, "", v4Conf, v6Conf, ipam.Options))
}
|
3ca29823 |
if create.Internal { |
b70954e6 |
nwOptions = append(nwOptions, libnetwork.NetworkOptionInternalNetwork())
} |
534a90a9 |
if agent {
nwOptions = append(nwOptions, libnetwork.NetworkOptionDynamic())
nwOptions = append(nwOptions, libnetwork.NetworkOptionPersist(false))
}
|
9ee7b4dd |
if create.ConfigFrom != nil {
nwOptions = append(nwOptions, libnetwork.NetworkOptionConfigFrom(create.ConfigFrom.Network))
}
|
8e0f6bc9 |
if agent && driver == "overlay" { |
41071d66 |
nodeIP, exists := daemon.GetAttachmentStore().GetIPForNetwork(id)
if !exists {
return nil, fmt.Errorf("Failed to find a load balancer IP to use for network: %v", id)
}
nwOptions = append(nwOptions, libnetwork.NetworkOptionLBEndpoint(nodeIP))
}
|
534a90a9 |
n, err := c.NewNetwork(driver, create.Name, id, nwOptions...) |
f15af1ef |
if err != nil { |
9c77a4c2 |
if _, ok := err.(libnetwork.ErrDataStoreNotInitialized); ok { |
9b47b7b1 |
// nolint: golint |
9c77a4c2 |
return nil, errors.New("This node is not a swarm manager. Use \"docker swarm init\" or \"docker swarm join\" to connect this node to swarm and try again.")
} |
f15af1ef |
return nil, err
}
|
42860010 |
daemon.pluginRefCount(driver, driverapi.NetworkPluginEndpointType, plugingetter.Acquire) |
fc2c0e62 |
if create.IPAM != nil { |
42860010 |
daemon.pluginRefCount(create.IPAM.Driver, ipamapi.PluginEndpointType, plugingetter.Acquire) |
fc2c0e62 |
} |
f15af1ef |
daemon.LogNetworkEvent(n, "create") |
3343d234 |
|
3ca29823 |
return &types.NetworkCreateResponse{
ID: n.ID(),
Warning: warning,
}, nil |
cc6aece1 |
}
|
fc2c0e62 |
func (daemon *Daemon) pluginRefCount(driver, capability string, mode int) {
var builtinDrivers []string
if capability == driverapi.NetworkPluginEndpointType {
builtinDrivers = daemon.netController.BuiltinDrivers()
} else if capability == ipamapi.PluginEndpointType {
builtinDrivers = daemon.netController.BuiltinIPAMDrivers()
}
for _, d := range builtinDrivers {
if d == driver {
return
}
}
if daemon.PluginStore != nil {
_, err := daemon.PluginStore.Get(driver, capability, mode)
if err != nil {
logrus.WithError(err).WithFields(logrus.Fields{"mode": mode, "driver": driver}).Error("Error handling plugin refcount operation")
}
}
}
|
cc6aece1 |
func getIpamConfig(data []network.IPAMConfig) ([]*libnetwork.IpamConf, []*libnetwork.IpamConf, error) {
ipamV4Cfg := []*libnetwork.IpamConf{}
ipamV6Cfg := []*libnetwork.IpamConf{}
for _, d := range data {
iCfg := libnetwork.IpamConf{}
iCfg.PreferredPool = d.Subnet
iCfg.SubPool = d.IPRange
iCfg.Gateway = d.Gateway
iCfg.AuxAddresses = d.AuxAddress
ip, _, err := net.ParseCIDR(d.Subnet)
if err != nil {
return nil, nil, fmt.Errorf("Invalid subnet %s : %v", d.Subnet, err)
}
if ip.To4() != nil {
ipamV4Cfg = append(ipamV4Cfg, &iCfg)
} else {
ipamV6Cfg = append(ipamV6Cfg, &iCfg)
}
}
return ipamV4Cfg, ipamV6Cfg, nil |
2ab94e11 |
} |
a0398fbd |
|
534a90a9 |
// UpdateContainerServiceConfig updates a service configuration.
func (daemon *Daemon) UpdateContainerServiceConfig(containerName string, serviceConfig *clustertypes.ServiceConfig) error {
container, err := daemon.GetContainer(containerName)
if err != nil {
return err
}
container.NetworkSettings.Service = serviceConfig
return nil
}
|
a0398fbd |
// ConnectContainerToNetwork connects the given container to the given
// network. If either cannot be found, an err is returned. If the
// network cannot be set up, an err is returned. |
2bb3fc1b |
func (daemon *Daemon) ConnectContainerToNetwork(containerName, networkName string, endpointConfig *network.EndpointSettings) error { |
d7d512bb |
container, err := daemon.GetContainer(containerName) |
a0398fbd |
if err != nil {
return err
} |
2bb3fc1b |
return daemon.ConnectToNetwork(container, networkName, endpointConfig) |
a0398fbd |
}
// DisconnectContainerFromNetwork disconnects the given container from
// the given network. If either cannot be found, an err is returned. |
05a3f266 |
func (daemon *Daemon) DisconnectContainerFromNetwork(containerName string, networkName string, force bool) error { |
d7d512bb |
container, err := daemon.GetContainer(containerName) |
a0398fbd |
if err != nil { |
b464f1d7 |
if force { |
05a3f266 |
return daemon.ForceEndpointDelete(containerName, networkName) |
b464f1d7 |
} |
a0398fbd |
return err
} |
05a3f266 |
return daemon.DisconnectFromNetwork(container, networkName, force) |
a0398fbd |
} |
aa7fd884 |
// GetNetworkDriverList returns the list of plugins drivers
// registered for network. |
7ca635a1 |
func (daemon *Daemon) GetNetworkDriverList() []string { |
37d2a700 |
if !daemon.NetworkControllerEnabled() {
return nil
} |
ea266f8f |
|
5e9c78ae |
pluginList := daemon.netController.BuiltinDrivers() |
6aaa85f0 |
managedPlugins := daemon.PluginStore.GetAllManagedPluginsByCap(driverapi.NetworkPluginEndpointType)
for _, plugin := range managedPlugins {
pluginList = append(pluginList, plugin.Name())
}
|
5e9c78ae |
pluginMap := make(map[string]bool) |
3347aba9 |
for _, plugin := range pluginList {
pluginMap[plugin] = true
} |
ea266f8f |
|
7ca635a1 |
networks := daemon.netController.Networks() |
aa7fd884 |
for _, network := range networks { |
7ca635a1 |
if !pluginMap[network.Type()] {
pluginList = append(pluginList, network.Type())
pluginMap[network.Type()] = true
} |
aa7fd884 |
} |
7ca635a1 |
sort.Strings(pluginList) |
aa7fd884 |
return pluginList
} |
f15af1ef |
|
534a90a9 |
// DeleteManagedNetwork deletes an agent network. |
cafed80c |
// The requirement of networkID is enforced. |
534a90a9 |
func (daemon *Daemon) DeleteManagedNetwork(networkID string) error { |
cafed80c |
n, err := daemon.GetNetworkByID(networkID)
if err != nil {
return err
}
return daemon.deleteNetwork(n, true) |
534a90a9 |
}
|
f15af1ef |
// DeleteNetwork destroys a network unless it's one of docker's predefined networks.
func (daemon *Daemon) DeleteNetwork(networkID string) error { |
cafed80c |
n, err := daemon.GetNetworkByID(networkID) |
f15af1ef |
if err != nil { |
c0bc14e8 |
return errors.Wrap(err, "could not find network by ID") |
f15af1ef |
} |
cafed80c |
return daemon.deleteNetwork(n, false)
} |
f15af1ef |
|
cafed80c |
func (daemon *Daemon) deleteNetwork(nw libnetwork.Network, dynamic bool) error { |
534a90a9 |
if runconfig.IsPreDefinedNetwork(nw.Name()) && !dynamic { |
a793564b |
err := fmt.Errorf("%s is a pre-defined network and cannot be removed", nw.Name()) |
87a12421 |
return errdefs.Forbidden(err) |
f15af1ef |
}
|
b34d3e73 |
if dynamic && !nw.Info().Dynamic() {
if runconfig.IsPreDefinedNetwork(nw.Name()) {
// Predefined networks now support swarm services. Make this
// a no-op when cluster requests to remove the predefined network.
return nil
}
err := fmt.Errorf("%s is not a dynamic network", nw.Name()) |
87a12421 |
return errdefs.Forbidden(err) |
b34d3e73 |
}
|
f15af1ef |
if err := nw.Delete(); err != nil { |
c0bc14e8 |
return errors.Wrap(err, "error while removing network") |
f15af1ef |
} |
9ee7b4dd |
// If this is not a configuration only network, we need to
// update the corresponding remote drivers' reference counts
if !nw.Info().ConfigOnly() {
daemon.pluginRefCount(nw.Type(), driverapi.NetworkPluginEndpointType, plugingetter.Release)
ipamType, _, _, _ := nw.Info().IpamConfig()
daemon.pluginRefCount(ipamType, ipamapi.PluginEndpointType, plugingetter.Release)
daemon.LogNetworkEvent(nw, "destroy")
}
|
f15af1ef |
return nil
} |
3ca29823 |
|
534a90a9 |
// GetNetworks returns a list of all networks |
c0bc14e8 |
func (daemon *Daemon) GetNetworks(filter filters.Args, config types.NetworkListConfig) ([]types.NetworkResource, error) {
networks := daemon.getAllNetworks()
list := make([]types.NetworkResource, 0, len(networks))
var idx map[string]libnetwork.Network
if config.Detailed {
idx = make(map[string]libnetwork.Network)
}
for _, n := range networks {
nr := buildNetworkResource(n)
list = append(list, nr)
if config.Detailed {
idx[nr.ID] = n
}
}
var err error
list, err = internalnetwork.FilterNetworks(list, filter)
if err != nil {
return nil, err
}
if config.Detailed {
for i, n := range list {
np := &n
buildDetailedNetworkResources(np, idx[n.ID], config.Verbose)
list[i] = *np
}
}
return list, nil
}
func buildNetworkResource(nw libnetwork.Network) types.NetworkResource {
r := types.NetworkResource{}
if nw == nil {
return r
}
info := nw.Info()
r.Name = nw.Name()
r.ID = nw.ID()
r.Created = info.Created()
r.Scope = info.Scope()
r.Driver = nw.Type()
r.EnableIPv6 = info.IPv6Enabled()
r.Internal = info.Internal()
r.Attachable = info.Attachable()
r.Ingress = info.Ingress()
r.Options = info.DriverOptions()
r.Containers = make(map[string]types.EndpointResource)
buildIpamResources(&r, info)
r.Labels = info.Labels()
r.ConfigOnly = info.ConfigOnly()
if cn := info.ConfigFrom(); cn != "" {
r.ConfigFrom = network.ConfigReference{Network: cn}
}
peers := info.Peers()
if len(peers) != 0 {
r.Peers = buildPeerInfoResources(peers)
}
return r
}
func buildDetailedNetworkResources(r *types.NetworkResource, nw libnetwork.Network, verbose bool) {
if nw == nil {
return
}
epl := nw.Endpoints()
for _, e := range epl {
ei := e.Info()
if ei == nil {
continue
}
sb := ei.Sandbox()
tmpID := e.ID()
key := "ep-" + tmpID
if sb != nil {
key = sb.ContainerID()
}
r.Containers[key] = buildEndpointResource(tmpID, e.Name(), ei)
}
if !verbose {
return
}
services := nw.Info().Services()
r.Services = make(map[string]network.ServiceInfo)
for name, service := range services {
tasks := []network.Task{}
for _, t := range service.Tasks {
tasks = append(tasks, network.Task{
Name: t.Name,
EndpointID: t.EndpointID,
EndpointIP: t.EndpointIP,
Info: t.Info,
})
}
r.Services[name] = network.ServiceInfo{
VIP: service.VIP,
Ports: service.Ports,
Tasks: tasks,
LocalLBIndex: service.LocalLBIndex,
}
}
}
func buildPeerInfoResources(peers []networkdb.PeerInfo) []network.PeerInfo {
peerInfo := make([]network.PeerInfo, 0, len(peers))
for _, peer := range peers {
peerInfo = append(peerInfo, network.PeerInfo{
Name: peer.Name,
IP: peer.IP,
})
}
return peerInfo
}
func buildIpamResources(r *types.NetworkResource, nwInfo libnetwork.NetworkInfo) {
id, opts, ipv4conf, ipv6conf := nwInfo.IpamConfig()
ipv4Info, ipv6Info := nwInfo.IpamInfo()
r.IPAM.Driver = id
r.IPAM.Options = opts
r.IPAM.Config = []network.IPAMConfig{}
for _, ip4 := range ipv4conf {
if ip4.PreferredPool == "" {
continue
}
iData := network.IPAMConfig{}
iData.Subnet = ip4.PreferredPool
iData.IPRange = ip4.SubPool
iData.Gateway = ip4.Gateway
iData.AuxAddress = ip4.AuxAddresses
r.IPAM.Config = append(r.IPAM.Config, iData)
}
if len(r.IPAM.Config) == 0 {
for _, ip4Info := range ipv4Info {
iData := network.IPAMConfig{}
iData.Subnet = ip4Info.IPAMData.Pool.String()
if ip4Info.IPAMData.Gateway != nil {
iData.Gateway = ip4Info.IPAMData.Gateway.IP.String()
}
r.IPAM.Config = append(r.IPAM.Config, iData)
}
}
hasIpv6Conf := false
for _, ip6 := range ipv6conf {
if ip6.PreferredPool == "" {
continue
}
hasIpv6Conf = true
iData := network.IPAMConfig{}
iData.Subnet = ip6.PreferredPool
iData.IPRange = ip6.SubPool
iData.Gateway = ip6.Gateway
iData.AuxAddress = ip6.AuxAddresses
r.IPAM.Config = append(r.IPAM.Config, iData)
}
if !hasIpv6Conf {
for _, ip6Info := range ipv6Info {
if ip6Info.IPAMData.Pool == nil {
continue
}
iData := network.IPAMConfig{}
iData.Subnet = ip6Info.IPAMData.Pool.String()
iData.Gateway = ip6Info.IPAMData.Gateway.String()
r.IPAM.Config = append(r.IPAM.Config, iData)
}
}
}
func buildEndpointResource(id string, name string, info libnetwork.EndpointInfo) types.EndpointResource {
er := types.EndpointResource{}
er.EndpointID = id
er.Name = name
ei := info
if ei == nil {
return er
}
if iface := ei.Iface(); iface != nil {
if mac := iface.MacAddress(); mac != nil {
er.MacAddress = mac.String()
}
if ip := iface.Address(); ip != nil && len(ip.IP) > 0 {
er.IPv4Address = ip.String()
}
if ipv6 := iface.AddressIPv6(); ipv6 != nil && len(ipv6.IP) > 0 {
er.IPv6Address = ipv6.String()
}
}
return er |
3ca29823 |
} |
3cedca5d |
// clearAttachableNetworks removes the attachable networks
// after disconnecting any connected container
func (daemon *Daemon) clearAttachableNetworks() { |
cc8f358c |
for _, n := range daemon.getAllNetworks() { |
3cedca5d |
if !n.Info().Attachable() {
continue
}
for _, ep := range n.Endpoints() {
epInfo := ep.Info()
if epInfo == nil {
continue
}
sb := epInfo.Sandbox()
if sb == nil {
continue
}
containerID := sb.ContainerID()
if err := daemon.DisconnectContainerFromNetwork(containerID, n.ID(), true); err != nil {
logrus.Warnf("Failed to disconnect container %s from swarm network %s on cluster leave: %v",
containerID, n.Name(), err)
}
}
if err := daemon.DeleteManagedNetwork(n.ID()); err != nil {
logrus.Warnf("Failed to remove swarm network %s on cluster leave: %v", n.Name(), err)
}
}
} |
cc8f358c |
// 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()
|
20dde018 |
if (!serviceDiscoveryOnDefaultNetwork() && n.Name() == defaultNetName) || |
cc8f358c |
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
} |