mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Add support for docker run in swarm mode overlay
This PR adds support for running regular containers to be connected to swarm mode multi-host network so that: - containers connected to the same network across the cluster can discover and connect to each other. - Get access to services(and their associated loadbalancers) connected to the same network Signed-off-by: Jana Radhakrishnan <mrjana@docker.com>
This commit is contained in:
parent
99c3968098
commit
99a98ccc14
23 changed files with 606 additions and 104 deletions
|
@ -23,6 +23,7 @@ type createOptions struct {
|
||||||
labels []string
|
labels []string
|
||||||
internal bool
|
internal bool
|
||||||
ipv6 bool
|
ipv6 bool
|
||||||
|
attachable bool
|
||||||
|
|
||||||
ipamDriver string
|
ipamDriver string
|
||||||
ipamSubnet []string
|
ipamSubnet []string
|
||||||
|
@ -55,6 +56,7 @@ func newCreateCommand(dockerCli *client.DockerCli) *cobra.Command {
|
||||||
flags.StringSliceVar(&opts.labels, "label", []string{}, "Set metadata on a network")
|
flags.StringSliceVar(&opts.labels, "label", []string{}, "Set metadata on a network")
|
||||||
flags.BoolVar(&opts.internal, "internal", false, "Restrict external access to the network")
|
flags.BoolVar(&opts.internal, "internal", false, "Restrict external access to the network")
|
||||||
flags.BoolVar(&opts.ipv6, "ipv6", false, "Enable IPv6 networking")
|
flags.BoolVar(&opts.ipv6, "ipv6", false, "Enable IPv6 networking")
|
||||||
|
flags.BoolVar(&opts.attachable, "attachable", false, "Enable manual container attachment")
|
||||||
|
|
||||||
flags.StringVar(&opts.ipamDriver, "ipam-driver", "default", "IP Address Management Driver")
|
flags.StringVar(&opts.ipamDriver, "ipam-driver", "default", "IP Address Management Driver")
|
||||||
flags.StringSliceVar(&opts.ipamSubnet, "subnet", []string{}, "Subnet in CIDR format that represents a network segment")
|
flags.StringSliceVar(&opts.ipamSubnet, "subnet", []string{}, "Subnet in CIDR format that represents a network segment")
|
||||||
|
@ -87,6 +89,7 @@ func runCreate(dockerCli *client.DockerCli, opts createOptions) error {
|
||||||
CheckDuplicate: true,
|
CheckDuplicate: true,
|
||||||
Internal: opts.internal,
|
Internal: opts.internal,
|
||||||
EnableIPv6: opts.ipv6,
|
EnableIPv6: opts.ipv6,
|
||||||
|
Attachable: opts.attachable,
|
||||||
Labels: runconfigopts.ConvertKVStringsToMap(opts.labels),
|
Labels: runconfigopts.ConvertKVStringsToMap(opts.labels),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -451,6 +451,7 @@ func (opts *serviceOptions) ToService() (swarm.ServiceSpec, error) {
|
||||||
Mounts: opts.mounts.Value(),
|
Mounts: opts.mounts.Value(),
|
||||||
StopGracePeriod: opts.stopGrace.Value(),
|
StopGracePeriod: opts.stopGrace.Value(),
|
||||||
},
|
},
|
||||||
|
Networks: convertNetworks(opts.networks),
|
||||||
Resources: opts.resources.ToResourceRequirements(),
|
Resources: opts.resources.ToResourceRequirements(),
|
||||||
RestartPolicy: opts.restartPolicy.ToRestartPolicy(),
|
RestartPolicy: opts.restartPolicy.ToRestartPolicy(),
|
||||||
Placement: &swarm.Placement{
|
Placement: &swarm.Placement{
|
||||||
|
@ -458,13 +459,13 @@ func (opts *serviceOptions) ToService() (swarm.ServiceSpec, error) {
|
||||||
},
|
},
|
||||||
LogDriver: opts.logDriver.toLogDriver(),
|
LogDriver: opts.logDriver.toLogDriver(),
|
||||||
},
|
},
|
||||||
Mode: swarm.ServiceMode{},
|
Networks: convertNetworks(opts.networks),
|
||||||
|
Mode: swarm.ServiceMode{},
|
||||||
UpdateConfig: &swarm.UpdateConfig{
|
UpdateConfig: &swarm.UpdateConfig{
|
||||||
Parallelism: opts.update.parallelism,
|
Parallelism: opts.update.parallelism,
|
||||||
Delay: opts.update.delay,
|
Delay: opts.update.delay,
|
||||||
FailureAction: opts.update.onFailure,
|
FailureAction: opts.update.onFailure,
|
||||||
},
|
},
|
||||||
Networks: convertNetworks(opts.networks),
|
|
||||||
EndpointSpec: opts.endpoint.ToEndpointSpec(),
|
EndpointSpec: opts.endpoint.ToEndpointSpec(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@ package network
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
|
@ -11,7 +10,6 @@ import (
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/filters"
|
"github.com/docker/docker/api/types/filters"
|
||||||
"github.com/docker/docker/api/types/network"
|
"github.com/docker/docker/api/types/network"
|
||||||
"github.com/docker/docker/errors"
|
|
||||||
"github.com/docker/libnetwork"
|
"github.com/docker/libnetwork"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -116,17 +114,7 @@ func (n *networkRouter) postNetworkConnect(ctx context.Context, w http.ResponseW
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
nw, err := n.backend.FindNetwork(vars["id"])
|
return n.backend.ConnectContainerToNetwork(connect.Container, vars["id"], connect.EndpointConfig)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if nw.Info().Dynamic() {
|
|
||||||
err := fmt.Errorf("operation not supported for swarm scoped networks")
|
|
||||||
return errors.NewRequestForbiddenError(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return n.backend.ConnectContainerToNetwork(connect.Container, nw.Name(), connect.EndpointConfig)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *networkRouter) postNetworkDisconnect(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
func (n *networkRouter) postNetworkDisconnect(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||||
|
@ -143,13 +131,6 @@ func (n *networkRouter) postNetworkDisconnect(ctx context.Context, w http.Respon
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
nw, _ := n.backend.FindNetwork(vars["id"])
|
|
||||||
|
|
||||||
if nw != nil && nw.Info().Dynamic() {
|
|
||||||
err := fmt.Errorf("operation not supported for swarm scoped networks")
|
|
||||||
return errors.NewRequestForbiddenError(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return n.backend.DisconnectContainerFromNetwork(disconnect.Container, vars["id"], disconnect.Force)
|
return n.backend.DisconnectContainerFromNetwork(disconnect.Container, vars["id"], disconnect.Force)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -700,7 +700,9 @@ func (container *Container) BuildEndpointInfo(n libnetwork.Network, ep libnetwor
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := networkSettings.Networks[n.Name()]; !ok {
|
if _, ok := networkSettings.Networks[n.Name()]; !ok {
|
||||||
networkSettings.Networks[n.Name()] = new(networktypes.EndpointSettings)
|
networkSettings.Networks[n.Name()] = &network.EndpointSettings{
|
||||||
|
EndpointSettings: &networktypes.EndpointSettings{},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
networkSettings.Networks[n.Name()].NetworkID = n.ID()
|
networkSettings.Networks[n.Name()].NetworkID = n.ID()
|
||||||
networkSettings.Networks[n.Name()].EndpointID = ep.ID()
|
networkSettings.Networks[n.Name()].EndpointID = ep.ID()
|
||||||
|
|
|
@ -16,6 +16,7 @@ import (
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
apitypes "github.com/docker/docker/api/types"
|
apitypes "github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/filters"
|
"github.com/docker/docker/api/types/filters"
|
||||||
|
"github.com/docker/docker/api/types/network"
|
||||||
types "github.com/docker/docker/api/types/swarm"
|
types "github.com/docker/docker/api/types/swarm"
|
||||||
"github.com/docker/docker/daemon/cluster/convert"
|
"github.com/docker/docker/daemon/cluster/convert"
|
||||||
executorpkg "github.com/docker/docker/daemon/cluster/executor"
|
executorpkg "github.com/docker/docker/daemon/cluster/executor"
|
||||||
|
@ -126,6 +127,18 @@ type Cluster struct {
|
||||||
stop bool
|
stop bool
|
||||||
err error
|
err error
|
||||||
cancelDelay func()
|
cancelDelay func()
|
||||||
|
attachers map[string]*attacher
|
||||||
|
}
|
||||||
|
|
||||||
|
// attacher manages the in-memory attachment state of a container
|
||||||
|
// attachment to a global scope network managed by swarm manager. It
|
||||||
|
// helps in identifying the attachment ID via the taskID and the
|
||||||
|
// corresponding attachment configuration obtained from the manager.
|
||||||
|
type attacher struct {
|
||||||
|
taskID string
|
||||||
|
config *network.NetworkingConfig
|
||||||
|
attachWaitCh chan *network.NetworkingConfig
|
||||||
|
detachWaitCh chan struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
type node struct {
|
type node struct {
|
||||||
|
@ -154,6 +167,7 @@ func New(config Config) (*Cluster, error) {
|
||||||
config: config,
|
config: config,
|
||||||
configEvent: make(chan struct{}, 10),
|
configEvent: make(chan struct{}, 10),
|
||||||
runtimeRoot: config.RuntimeRoot,
|
runtimeRoot: config.RuntimeRoot,
|
||||||
|
attachers: make(map[string]*attacher),
|
||||||
}
|
}
|
||||||
|
|
||||||
st, err := c.loadState()
|
st, err := c.loadState()
|
||||||
|
@ -1212,6 +1226,120 @@ func (c *Cluster) GetNetworks() ([]apitypes.NetworkResource, error) {
|
||||||
return networks, nil
|
return networks, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func attacherKey(target, containerID string) string {
|
||||||
|
return containerID + ":" + target
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateAttachment signals the attachment config to the attachment
|
||||||
|
// waiter who is trying to start or attach the container to the
|
||||||
|
// network.
|
||||||
|
func (c *Cluster) UpdateAttachment(target, containerID string, config *network.NetworkingConfig) error {
|
||||||
|
c.RLock()
|
||||||
|
attacher, ok := c.attachers[attacherKey(target, containerID)]
|
||||||
|
c.RUnlock()
|
||||||
|
if !ok || attacher == nil {
|
||||||
|
return fmt.Errorf("could not find attacher for container %s to network %s", containerID, target)
|
||||||
|
}
|
||||||
|
|
||||||
|
attacher.attachWaitCh <- config
|
||||||
|
close(attacher.attachWaitCh)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// WaitForDetachment waits for the container to stop or detach from
|
||||||
|
// the network.
|
||||||
|
func (c *Cluster) WaitForDetachment(ctx context.Context, networkName, networkID, taskID, containerID string) error {
|
||||||
|
c.RLock()
|
||||||
|
attacher, ok := c.attachers[attacherKey(networkName, containerID)]
|
||||||
|
if !ok {
|
||||||
|
attacher, ok = c.attachers[attacherKey(networkID, containerID)]
|
||||||
|
}
|
||||||
|
if c.node == nil || c.node.Agent() == nil {
|
||||||
|
c.RUnlock()
|
||||||
|
return fmt.Errorf("invalid cluster node while waiting for detachment")
|
||||||
|
}
|
||||||
|
|
||||||
|
agent := c.node.Agent()
|
||||||
|
c.RUnlock()
|
||||||
|
|
||||||
|
if ok && attacher != nil && attacher.detachWaitCh != nil {
|
||||||
|
select {
|
||||||
|
case <-attacher.detachWaitCh:
|
||||||
|
case <-ctx.Done():
|
||||||
|
return ctx.Err()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return agent.ResourceAllocator().DetachNetwork(ctx, taskID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AttachNetwork generates an attachment request towards the manager.
|
||||||
|
func (c *Cluster) AttachNetwork(target string, containerID string, addresses []string) (*network.NetworkingConfig, error) {
|
||||||
|
aKey := attacherKey(target, containerID)
|
||||||
|
c.Lock()
|
||||||
|
if c.node == nil || c.node.Agent() == nil {
|
||||||
|
c.Unlock()
|
||||||
|
return nil, fmt.Errorf("invalid cluster node while attaching to network")
|
||||||
|
}
|
||||||
|
if attacher, ok := c.attachers[aKey]; ok {
|
||||||
|
c.Unlock()
|
||||||
|
return attacher.config, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
agent := c.node.Agent()
|
||||||
|
attachWaitCh := make(chan *network.NetworkingConfig)
|
||||||
|
detachWaitCh := make(chan struct{})
|
||||||
|
c.attachers[aKey] = &attacher{
|
||||||
|
attachWaitCh: attachWaitCh,
|
||||||
|
detachWaitCh: detachWaitCh,
|
||||||
|
}
|
||||||
|
c.Unlock()
|
||||||
|
|
||||||
|
ctx, cancel := c.getRequestContext()
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
taskID, err := agent.ResourceAllocator().AttachNetwork(ctx, containerID, target, addresses)
|
||||||
|
if err != nil {
|
||||||
|
c.Lock()
|
||||||
|
delete(c.attachers, aKey)
|
||||||
|
c.Unlock()
|
||||||
|
return nil, fmt.Errorf("Could not attach to network %s: %v", target, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Debugf("Successfully attached to network %s with tid %s", target, taskID)
|
||||||
|
|
||||||
|
var config *network.NetworkingConfig
|
||||||
|
select {
|
||||||
|
case config = <-attachWaitCh:
|
||||||
|
case <-ctx.Done():
|
||||||
|
return nil, fmt.Errorf("attaching to network failed, make sure your network options are correct and check manager logs: %v", ctx.Err())
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Lock()
|
||||||
|
c.attachers[aKey].taskID = taskID
|
||||||
|
c.attachers[aKey].config = config
|
||||||
|
c.Unlock()
|
||||||
|
return config, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DetachNetwork unblocks the waiters waiting on WaitForDetachment so
|
||||||
|
// that a request to detach can be generated towards the manager.
|
||||||
|
func (c *Cluster) DetachNetwork(target string, containerID string) error {
|
||||||
|
aKey := attacherKey(target, containerID)
|
||||||
|
|
||||||
|
c.Lock()
|
||||||
|
attacher, ok := c.attachers[aKey]
|
||||||
|
delete(c.attachers, aKey)
|
||||||
|
c.Unlock()
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("could not find network attachment for container %s to network %s", containerID, target)
|
||||||
|
}
|
||||||
|
|
||||||
|
close(attacher.detachWaitCh)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// CreateNetwork creates a new cluster managed network.
|
// CreateNetwork creates a new cluster managed network.
|
||||||
func (c *Cluster) CreateNetwork(s apitypes.NetworkCreateRequest) (string, error) {
|
func (c *Cluster) CreateNetwork(s apitypes.NetworkCreateRequest) (string, error) {
|
||||||
c.RLock()
|
c.RLock()
|
||||||
|
@ -1262,7 +1390,14 @@ func (c *Cluster) RemoveNetwork(input string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Cluster) populateNetworkID(ctx context.Context, client swarmapi.ControlClient, s *types.ServiceSpec) error {
|
func (c *Cluster) populateNetworkID(ctx context.Context, client swarmapi.ControlClient, s *types.ServiceSpec) error {
|
||||||
for i, n := range s.Networks {
|
// Always prefer NetworkAttachmentConfigs from TaskTemplate
|
||||||
|
// but fallback to service spec for backward compatibility
|
||||||
|
networks := s.TaskTemplate.Networks
|
||||||
|
if len(networks) == 0 {
|
||||||
|
networks = s.Networks
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, n := range networks {
|
||||||
apiNetwork, err := getNetwork(ctx, client, n.Target)
|
apiNetwork, err := getNetwork(ctx, client, n.Target)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if ln, _ := c.config.Backend.FindNetwork(n.Target); ln != nil && !ln.Info().Dynamic() {
|
if ln, _ := c.config.Backend.FindNetwork(n.Target); ln != nil && !ln.Info().Dynamic() {
|
||||||
|
@ -1271,7 +1406,7 @@ func (c *Cluster) populateNetworkID(ctx context.Context, client swarmapi.Control
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
s.Networks[i].Target = apiNetwork.ID
|
networks[i].Target = apiNetwork.ID
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ func networkFromGRPC(n *swarmapi.Network) types.Network {
|
||||||
Spec: types.NetworkSpec{
|
Spec: types.NetworkSpec{
|
||||||
IPv6Enabled: n.Spec.Ipv6Enabled,
|
IPv6Enabled: n.Spec.Ipv6Enabled,
|
||||||
Internal: n.Spec.Internal,
|
Internal: n.Spec.Internal,
|
||||||
|
Attachable: n.Spec.Attachable,
|
||||||
IPAMOptions: ipamFromGRPC(n.Spec.IPAM),
|
IPAMOptions: ipamFromGRPC(n.Spec.IPAM),
|
||||||
},
|
},
|
||||||
IPAMOptions: ipamFromGRPC(n.IPAM),
|
IPAMOptions: ipamFromGRPC(n.IPAM),
|
||||||
|
@ -155,6 +156,7 @@ func BasicNetworkFromGRPC(n swarmapi.Network) basictypes.NetworkResource {
|
||||||
EnableIPv6: spec.Ipv6Enabled,
|
EnableIPv6: spec.Ipv6Enabled,
|
||||||
IPAM: ipam,
|
IPAM: ipam,
|
||||||
Internal: spec.Internal,
|
Internal: spec.Internal,
|
||||||
|
Attachable: spec.Attachable,
|
||||||
Labels: n.Spec.Annotations.Labels,
|
Labels: n.Spec.Annotations.Labels,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,6 +181,7 @@ func BasicNetworkCreateToGRPC(create basictypes.NetworkCreateRequest) swarmapi.N
|
||||||
},
|
},
|
||||||
Ipv6Enabled: create.EnableIPv6,
|
Ipv6Enabled: create.EnableIPv6,
|
||||||
Internal: create.Internal,
|
Internal: create.Internal,
|
||||||
|
Attachable: create.Attachable,
|
||||||
}
|
}
|
||||||
if create.IPAM != nil {
|
if create.IPAM != nil {
|
||||||
ns.IPAM = &swarmapi.IPAMOptions{
|
ns.IPAM = &swarmapi.IPAMOptions{
|
||||||
|
|
|
@ -15,10 +15,16 @@ func ServiceFromGRPC(s swarmapi.Service) types.Service {
|
||||||
spec := s.Spec
|
spec := s.Spec
|
||||||
containerConfig := spec.Task.Runtime.(*swarmapi.TaskSpec_Container).Container
|
containerConfig := spec.Task.Runtime.(*swarmapi.TaskSpec_Container).Container
|
||||||
|
|
||||||
networks := make([]types.NetworkAttachmentConfig, 0, len(spec.Networks))
|
serviceNetworks := make([]types.NetworkAttachmentConfig, 0, len(spec.Networks))
|
||||||
for _, n := range spec.Networks {
|
for _, n := range spec.Networks {
|
||||||
networks = append(networks, types.NetworkAttachmentConfig{Target: n.Target, Aliases: n.Aliases})
|
serviceNetworks = append(serviceNetworks, types.NetworkAttachmentConfig{Target: n.Target, Aliases: n.Aliases})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
taskNetworks := make([]types.NetworkAttachmentConfig, 0, len(spec.Task.Networks))
|
||||||
|
for _, n := range spec.Task.Networks {
|
||||||
|
taskNetworks = append(taskNetworks, types.NetworkAttachmentConfig{Target: n.Target, Aliases: n.Aliases})
|
||||||
|
}
|
||||||
|
|
||||||
service := types.Service{
|
service := types.Service{
|
||||||
ID: s.ID,
|
ID: s.ID,
|
||||||
|
|
||||||
|
@ -29,9 +35,10 @@ func ServiceFromGRPC(s swarmapi.Service) types.Service {
|
||||||
RestartPolicy: restartPolicyFromGRPC(s.Spec.Task.Restart),
|
RestartPolicy: restartPolicyFromGRPC(s.Spec.Task.Restart),
|
||||||
Placement: placementFromGRPC(s.Spec.Task.Placement),
|
Placement: placementFromGRPC(s.Spec.Task.Placement),
|
||||||
LogDriver: driverFromGRPC(s.Spec.Task.LogDriver),
|
LogDriver: driverFromGRPC(s.Spec.Task.LogDriver),
|
||||||
|
Networks: taskNetworks,
|
||||||
},
|
},
|
||||||
|
|
||||||
Networks: networks,
|
Networks: serviceNetworks,
|
||||||
EndpointSpec: endpointSpecFromGRPC(s.Spec.Endpoint),
|
EndpointSpec: endpointSpecFromGRPC(s.Spec.Endpoint),
|
||||||
},
|
},
|
||||||
Endpoint: endpointFromGRPC(s.Endpoint),
|
Endpoint: endpointFromGRPC(s.Endpoint),
|
||||||
|
@ -99,9 +106,14 @@ func ServiceSpecToGRPC(s types.ServiceSpec) (swarmapi.ServiceSpec, error) {
|
||||||
name = namesgenerator.GetRandomName(0)
|
name = namesgenerator.GetRandomName(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
networks := make([]*swarmapi.ServiceSpec_NetworkAttachmentConfig, 0, len(s.Networks))
|
serviceNetworks := make([]*swarmapi.NetworkAttachmentConfig, 0, len(s.Networks))
|
||||||
for _, n := range s.Networks {
|
for _, n := range s.Networks {
|
||||||
networks = append(networks, &swarmapi.ServiceSpec_NetworkAttachmentConfig{Target: n.Target, Aliases: n.Aliases})
|
serviceNetworks = append(serviceNetworks, &swarmapi.NetworkAttachmentConfig{Target: n.Target, Aliases: n.Aliases})
|
||||||
|
}
|
||||||
|
|
||||||
|
taskNetworks := make([]*swarmapi.NetworkAttachmentConfig, 0, len(s.TaskTemplate.Networks))
|
||||||
|
for _, n := range s.TaskTemplate.Networks {
|
||||||
|
taskNetworks = append(taskNetworks, &swarmapi.NetworkAttachmentConfig{Target: n.Target, Aliases: n.Aliases})
|
||||||
}
|
}
|
||||||
|
|
||||||
spec := swarmapi.ServiceSpec{
|
spec := swarmapi.ServiceSpec{
|
||||||
|
@ -112,8 +124,9 @@ func ServiceSpecToGRPC(s types.ServiceSpec) (swarmapi.ServiceSpec, error) {
|
||||||
Task: swarmapi.TaskSpec{
|
Task: swarmapi.TaskSpec{
|
||||||
Resources: resourcesToGRPC(s.TaskTemplate.Resources),
|
Resources: resourcesToGRPC(s.TaskTemplate.Resources),
|
||||||
LogDriver: driverToGRPC(s.TaskTemplate.LogDriver),
|
LogDriver: driverToGRPC(s.TaskTemplate.LogDriver),
|
||||||
|
Networks: taskNetworks,
|
||||||
},
|
},
|
||||||
Networks: networks,
|
Networks: serviceNetworks,
|
||||||
}
|
}
|
||||||
|
|
||||||
containerSpec, err := containerToGRPC(s.TaskTemplate.ContainerSpec)
|
containerSpec, err := containerToGRPC(s.TaskTemplate.ContainerSpec)
|
||||||
|
|
|
@ -12,6 +12,11 @@ import (
|
||||||
func TaskFromGRPC(t swarmapi.Task) types.Task {
|
func TaskFromGRPC(t swarmapi.Task) types.Task {
|
||||||
containerConfig := t.Spec.Runtime.(*swarmapi.TaskSpec_Container).Container
|
containerConfig := t.Spec.Runtime.(*swarmapi.TaskSpec_Container).Container
|
||||||
containerStatus := t.Status.GetContainer()
|
containerStatus := t.Status.GetContainer()
|
||||||
|
networks := make([]types.NetworkAttachmentConfig, 0, len(t.Spec.Networks))
|
||||||
|
for _, n := range t.Spec.Networks {
|
||||||
|
networks = append(networks, types.NetworkAttachmentConfig{Target: n.Target, Aliases: n.Aliases})
|
||||||
|
}
|
||||||
|
|
||||||
task := types.Task{
|
task := types.Task{
|
||||||
ID: t.ID,
|
ID: t.ID,
|
||||||
ServiceID: t.ServiceID,
|
ServiceID: t.ServiceID,
|
||||||
|
@ -23,6 +28,7 @@ func TaskFromGRPC(t swarmapi.Task) types.Task {
|
||||||
RestartPolicy: restartPolicyFromGRPC(t.Spec.Restart),
|
RestartPolicy: restartPolicyFromGRPC(t.Spec.Restart),
|
||||||
Placement: placementFromGRPC(t.Spec.Placement),
|
Placement: placementFromGRPC(t.Spec.Placement),
|
||||||
LogDriver: driverFromGRPC(t.Spec.LogDriver),
|
LogDriver: driverFromGRPC(t.Spec.LogDriver),
|
||||||
|
Networks: networks,
|
||||||
},
|
},
|
||||||
Status: types.TaskStatus{
|
Status: types.TaskStatus{
|
||||||
State: types.TaskState(strings.ToLower(t.Status.State.String())),
|
State: types.TaskState(strings.ToLower(t.Status.State.String())),
|
||||||
|
|
|
@ -40,4 +40,6 @@ type Backend interface {
|
||||||
IsSwarmCompatible() error
|
IsSwarmCompatible() error
|
||||||
SubscribeToEvents(since, until time.Time, filter filters.Args) ([]events.Message, chan interface{})
|
SubscribeToEvents(since, until time.Time, filter filters.Args) ([]events.Message, chan interface{})
|
||||||
UnsubscribeFromEvents(listener chan interface{})
|
UnsubscribeFromEvents(listener chan interface{})
|
||||||
|
UpdateAttachment(string, string, string, *network.NetworkingConfig) error
|
||||||
|
WaitForDetachment(context.Context, string, string, string, string) error
|
||||||
}
|
}
|
||||||
|
|
|
@ -144,6 +144,44 @@ func (c *containerAdapter) removeNetworks(ctx context.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *containerAdapter) networkAttach(ctx context.Context) error {
|
||||||
|
config := c.container.createNetworkingConfig()
|
||||||
|
|
||||||
|
var (
|
||||||
|
networkName string
|
||||||
|
networkID string
|
||||||
|
)
|
||||||
|
|
||||||
|
if config != nil {
|
||||||
|
for n, epConfig := range config.EndpointsConfig {
|
||||||
|
networkName = n
|
||||||
|
networkID = epConfig.NetworkID
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.backend.UpdateAttachment(networkName, networkID, c.container.id(), config)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *containerAdapter) waitForDetach(ctx context.Context) error {
|
||||||
|
config := c.container.createNetworkingConfig()
|
||||||
|
|
||||||
|
var (
|
||||||
|
networkName string
|
||||||
|
networkID string
|
||||||
|
)
|
||||||
|
|
||||||
|
if config != nil {
|
||||||
|
for n, epConfig := range config.EndpointsConfig {
|
||||||
|
networkName = n
|
||||||
|
networkID = epConfig.NetworkID
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.backend.WaitForDetachment(ctx, networkName, networkID, c.container.taskID(), c.container.id())
|
||||||
|
}
|
||||||
|
|
||||||
func (c *containerAdapter) create(ctx context.Context) error {
|
func (c *containerAdapter) create(ctx context.Context) error {
|
||||||
var cr types.ContainerCreateResponse
|
var cr types.ContainerCreateResponse
|
||||||
var err error
|
var err error
|
||||||
|
@ -233,7 +271,7 @@ func (c *containerAdapter) events(ctx context.Context) <-chan events.Message {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *containerAdapter) wait(ctx context.Context) error {
|
func (c *containerAdapter) wait(ctx context.Context) error {
|
||||||
return c.backend.ContainerWaitWithContext(ctx, c.container.name())
|
return c.backend.ContainerWaitWithContext(ctx, c.container.nameOrID())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *containerAdapter) shutdown(ctx context.Context) error {
|
func (c *containerAdapter) shutdown(ctx context.Context) error {
|
||||||
|
|
80
daemon/cluster/executor/container/attachment.go
Normal file
80
daemon/cluster/executor/container/attachment.go
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
package container
|
||||||
|
|
||||||
|
import (
|
||||||
|
executorpkg "github.com/docker/docker/daemon/cluster/executor"
|
||||||
|
"github.com/docker/swarmkit/api"
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
)
|
||||||
|
|
||||||
|
// networkAttacherController implements agent.Controller against docker's API.
|
||||||
|
//
|
||||||
|
// networkAttacherController manages the lifecycle of network
|
||||||
|
// attachment of a docker unmanaged container managed as a task from
|
||||||
|
// agent point of view. It provides network attachment information to
|
||||||
|
// the unmanaged container for it to attach to the network and run.
|
||||||
|
type networkAttacherController struct {
|
||||||
|
backend executorpkg.Backend
|
||||||
|
task *api.Task
|
||||||
|
adapter *containerAdapter
|
||||||
|
closed chan struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newNetworkAttacherController(b executorpkg.Backend, task *api.Task) (*networkAttacherController, error) {
|
||||||
|
adapter, err := newContainerAdapter(b, task)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &networkAttacherController{
|
||||||
|
backend: b,
|
||||||
|
task: task,
|
||||||
|
adapter: adapter,
|
||||||
|
closed: make(chan struct{}),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nc *networkAttacherController) Update(ctx context.Context, t *api.Task) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nc *networkAttacherController) Prepare(ctx context.Context) error {
|
||||||
|
// Make sure all the networks that the task needs are created.
|
||||||
|
if err := nc.adapter.createNetworks(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nc *networkAttacherController) Start(ctx context.Context) error {
|
||||||
|
return nc.adapter.networkAttach(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nc *networkAttacherController) Wait(pctx context.Context) error {
|
||||||
|
ctx, cancel := context.WithCancel(pctx)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
return nc.adapter.waitForDetach(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nc *networkAttacherController) Shutdown(ctx context.Context) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nc *networkAttacherController) Terminate(ctx context.Context) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nc *networkAttacherController) Remove(ctx context.Context) error {
|
||||||
|
// Try removing the network referenced in this task in case this
|
||||||
|
// task is the last one referencing it
|
||||||
|
if err := nc.adapter.removeNetworks(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nc *networkAttacherController) Close() error {
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -44,17 +44,19 @@ func newContainerConfig(t *api.Task) (*containerConfig, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *containerConfig) setTask(t *api.Task) error {
|
func (c *containerConfig) setTask(t *api.Task) error {
|
||||||
container := t.Spec.GetContainer()
|
if t.Spec.GetContainer() == nil && t.Spec.GetAttachment() == nil {
|
||||||
if container == nil {
|
|
||||||
return exec.ErrRuntimeUnsupported
|
return exec.ErrRuntimeUnsupported
|
||||||
}
|
}
|
||||||
|
|
||||||
if container.Image == "" {
|
container := t.Spec.GetContainer()
|
||||||
return ErrImageRequired
|
if container != nil {
|
||||||
}
|
if container.Image == "" {
|
||||||
|
return ErrImageRequired
|
||||||
|
}
|
||||||
|
|
||||||
if err := validateMounts(container.Mounts); err != nil {
|
if err := validateMounts(container.Mounts); err != nil {
|
||||||
return err
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// index the networks by name
|
// index the networks by name
|
||||||
|
@ -67,6 +69,19 @@ func (c *containerConfig) setTask(t *api.Task) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *containerConfig) id() string {
|
||||||
|
attachment := c.task.Spec.GetAttachment()
|
||||||
|
if attachment == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return attachment.ContainerID
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *containerConfig) taskID() string {
|
||||||
|
return c.task.ID
|
||||||
|
}
|
||||||
|
|
||||||
func (c *containerConfig) endpoint() *api.Endpoint {
|
func (c *containerConfig) endpoint() *api.Endpoint {
|
||||||
return c.task.Endpoint
|
return c.task.Endpoint
|
||||||
}
|
}
|
||||||
|
@ -75,6 +90,14 @@ func (c *containerConfig) spec() *api.ContainerSpec {
|
||||||
return c.task.Spec.GetContainer()
|
return c.task.Spec.GetContainer()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *containerConfig) nameOrID() string {
|
||||||
|
if c.task.Spec.GetContainer() != nil {
|
||||||
|
return c.name()
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.id()
|
||||||
|
}
|
||||||
|
|
||||||
func (c *containerConfig) name() string {
|
func (c *containerConfig) name() string {
|
||||||
if c.task.Annotations.Name != "" {
|
if c.task.Annotations.Name != "" {
|
||||||
// if set, use the container Annotations.Name field, set in the orchestrator.
|
// if set, use the container Annotations.Name field, set in the orchestrator.
|
||||||
|
@ -342,7 +365,7 @@ func (c *containerConfig) resources() enginecontainer.Resources {
|
||||||
// Docker daemon supports just 1 network during container create.
|
// Docker daemon supports just 1 network during container create.
|
||||||
func (c *containerConfig) createNetworkingConfig() *network.NetworkingConfig {
|
func (c *containerConfig) createNetworkingConfig() *network.NetworkingConfig {
|
||||||
var networks []*api.NetworkAttachment
|
var networks []*api.NetworkAttachment
|
||||||
if c.task.Spec.GetContainer() != nil {
|
if c.task.Spec.GetContainer() != nil || c.task.Spec.GetAttachment() != nil {
|
||||||
networks = c.task.Networks
|
networks = c.task.Networks
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -392,6 +415,7 @@ func getEndpointConfig(na *api.NetworkAttachment) *network.EndpointSettings {
|
||||||
}
|
}
|
||||||
|
|
||||||
return &network.EndpointSettings{
|
return &network.EndpointSettings{
|
||||||
|
NetworkID: na.Network.ID,
|
||||||
IPAMConfig: &network.EndpointIPAMConfig{
|
IPAMConfig: &network.EndpointIPAMConfig{
|
||||||
IPv4Address: ipv4,
|
IPv4Address: ipv4,
|
||||||
IPv6Address: ipv6,
|
IPv6Address: ipv6,
|
||||||
|
|
|
@ -121,6 +121,10 @@ func (e *executor) Configure(ctx context.Context, node *api.Node) error {
|
||||||
|
|
||||||
// Controller returns a docker container runner.
|
// Controller returns a docker container runner.
|
||||||
func (e *executor) Controller(t *api.Task) (exec.Controller, error) {
|
func (e *executor) Controller(t *api.Task) (exec.Controller, error) {
|
||||||
|
if t.Spec.GetAttachment() != nil {
|
||||||
|
return newNetworkAttacherController(e.backend, t)
|
||||||
|
}
|
||||||
|
|
||||||
ctlr, err := newController(e.backend, t)
|
ctlr, err := newController(e.backend, t)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -178,7 +178,7 @@ func (daemon *Daemon) buildSandboxOptions(container *container.Container) ([]lib
|
||||||
// return if this call to build join options is not for default bridge network
|
// return if this call to build join options is not for default bridge network
|
||||||
// Legacy Link is only supported by docker run --link
|
// Legacy Link is only supported by docker run --link
|
||||||
bridgeSettings, ok := container.NetworkSettings.Networks[defaultNetName]
|
bridgeSettings, ok := container.NetworkSettings.Networks[defaultNetName]
|
||||||
if !ok {
|
if !ok || bridgeSettings.EndpointSettings == nil {
|
||||||
return sboxOptions, nil
|
return sboxOptions, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -238,9 +238,9 @@ func (daemon *Daemon) buildSandboxOptions(container *container.Container) ([]lib
|
||||||
return sboxOptions, nil
|
return sboxOptions, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (daemon *Daemon) updateNetworkSettings(container *container.Container, n libnetwork.Network) error {
|
func (daemon *Daemon) updateNetworkSettings(container *container.Container, n libnetwork.Network, endpointConfig *networktypes.EndpointSettings) error {
|
||||||
if container.NetworkSettings == nil {
|
if container.NetworkSettings == nil {
|
||||||
container.NetworkSettings = &network.Settings{Networks: make(map[string]*networktypes.EndpointSettings)}
|
container.NetworkSettings = &network.Settings{Networks: make(map[string]*network.EndpointSettings)}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !container.HostConfig.NetworkMode.IsHost() && containertypes.NetworkMode(n.Type()).IsHost() {
|
if !container.HostConfig.NetworkMode.IsHost() && containertypes.NetworkMode(n.Type()).IsHost() {
|
||||||
|
@ -268,7 +268,9 @@ func (daemon *Daemon) updateNetworkSettings(container *container.Container, n li
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := container.NetworkSettings.Networks[n.Name()]; !ok {
|
if _, ok := container.NetworkSettings.Networks[n.Name()]; !ok {
|
||||||
container.NetworkSettings.Networks[n.Name()] = new(networktypes.EndpointSettings)
|
container.NetworkSettings.Networks[n.Name()] = &network.EndpointSettings{
|
||||||
|
EndpointSettings: endpointConfig,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -331,12 +333,63 @@ func errClusterNetworkOnRun(n string) error {
|
||||||
return fmt.Errorf("swarm-scoped network (%s) is not compatible with `docker create` or `docker run`. This network can only be used by a docker service", n)
|
return fmt.Errorf("swarm-scoped network (%s) is not compatible with `docker create` or `docker run`. This network can only be used by a docker service", n)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (daemon *Daemon) findAndAttachNetwork(container *container.Container, idOrName string, epConfig *networktypes.EndpointSettings) (libnetwork.Network, *networktypes.NetworkingConfig, error) {
|
||||||
|
n, err := daemon.FindNetwork(idOrName)
|
||||||
|
if err != nil {
|
||||||
|
// We should always be able to find the network for a
|
||||||
|
// managed container.
|
||||||
|
if container.Managed {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we found a network and if it is not dynamically created
|
||||||
|
// we should never attempt to attach to that network here.
|
||||||
|
if n != nil {
|
||||||
|
if container.Managed || !n.Info().Dynamic() {
|
||||||
|
return n, nil, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var addresses []string
|
||||||
|
if epConfig != nil && epConfig.IPAMConfig != nil {
|
||||||
|
if epConfig.IPAMConfig.IPv4Address != "" {
|
||||||
|
addresses = append(addresses, epConfig.IPAMConfig.IPv4Address)
|
||||||
|
}
|
||||||
|
|
||||||
|
if epConfig.IPAMConfig.IPv6Address != "" {
|
||||||
|
addresses = append(addresses, epConfig.IPAMConfig.IPv6Address)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// In all other cases, attempt to attach to the network to
|
||||||
|
// trigger attachment in the swarm cluster manager.
|
||||||
|
var config *networktypes.NetworkingConfig
|
||||||
|
if daemon.clusterProvider != nil {
|
||||||
|
var err error
|
||||||
|
config, err = daemon.clusterProvider.AttachNetwork(idOrName, container.ID, addresses)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
n, err = daemon.FindNetwork(idOrName)
|
||||||
|
if err != nil {
|
||||||
|
if daemon.clusterProvider != nil {
|
||||||
|
if err := daemon.clusterProvider.DetachNetwork(idOrName, container.ID); err != nil {
|
||||||
|
logrus.Warnf("Could not rollback attachment for container %s to network %s: %v", container.ID, idOrName, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return n, config, nil
|
||||||
|
}
|
||||||
|
|
||||||
// updateContainerNetworkSettings update the network settings
|
// updateContainerNetworkSettings update the network settings
|
||||||
func (daemon *Daemon) updateContainerNetworkSettings(container *container.Container, endpointsConfig map[string]*networktypes.EndpointSettings) error {
|
func (daemon *Daemon) updateContainerNetworkSettings(container *container.Container, endpointsConfig map[string]*networktypes.EndpointSettings) error {
|
||||||
var (
|
var n libnetwork.Network
|
||||||
n libnetwork.Network
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
|
|
||||||
mode := container.HostConfig.NetworkMode
|
mode := container.HostConfig.NetworkMode
|
||||||
if container.Config.NetworkDisabled || mode.IsContainer() {
|
if container.Config.NetworkDisabled || mode.IsContainer() {
|
||||||
|
@ -347,26 +400,48 @@ func (daemon *Daemon) updateContainerNetworkSettings(container *container.Contai
|
||||||
if mode.IsDefault() {
|
if mode.IsDefault() {
|
||||||
networkName = daemon.netController.Config().Daemon.DefaultNetwork
|
networkName = daemon.netController.Config().Daemon.DefaultNetwork
|
||||||
}
|
}
|
||||||
|
|
||||||
if mode.IsUserDefined() {
|
if mode.IsUserDefined() {
|
||||||
|
var err error
|
||||||
|
|
||||||
n, err = daemon.FindNetwork(networkName)
|
n, err = daemon.FindNetwork(networkName)
|
||||||
if err != nil {
|
if err == nil {
|
||||||
return err
|
networkName = n.Name()
|
||||||
}
|
}
|
||||||
if !container.Managed && n.Info().Dynamic() {
|
|
||||||
return errClusterNetworkOnRun(networkName)
|
|
||||||
}
|
|
||||||
networkName = n.Name()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if container.NetworkSettings == nil {
|
if container.NetworkSettings == nil {
|
||||||
container.NetworkSettings = &network.Settings{}
|
container.NetworkSettings = &network.Settings{}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(endpointsConfig) > 0 {
|
if len(endpointsConfig) > 0 {
|
||||||
container.NetworkSettings.Networks = endpointsConfig
|
if container.NetworkSettings.Networks == nil {
|
||||||
|
container.NetworkSettings.Networks = make(map[string]*network.EndpointSettings)
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, epConfig := range endpointsConfig {
|
||||||
|
container.NetworkSettings.Networks[name] = &network.EndpointSettings{
|
||||||
|
EndpointSettings: epConfig,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if container.NetworkSettings.Networks == nil {
|
if container.NetworkSettings.Networks == nil {
|
||||||
container.NetworkSettings.Networks = make(map[string]*networktypes.EndpointSettings)
|
container.NetworkSettings.Networks = make(map[string]*network.EndpointSettings)
|
||||||
container.NetworkSettings.Networks[networkName] = new(networktypes.EndpointSettings)
|
container.NetworkSettings.Networks[networkName] = &network.EndpointSettings{
|
||||||
|
EndpointSettings: &networktypes.EndpointSettings{},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Convert any settings added by client in default name to
|
||||||
|
// engine's default network name key
|
||||||
|
if mode.IsDefault() {
|
||||||
|
if nConf, ok := container.NetworkSettings.Networks[mode.NetworkName()]; ok {
|
||||||
|
container.NetworkSettings.Networks[networkName] = nConf
|
||||||
|
delete(container.NetworkSettings.Networks, mode.NetworkName())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if !mode.IsUserDefined() {
|
if !mode.IsUserDefined() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -374,10 +449,13 @@ func (daemon *Daemon) updateContainerNetworkSettings(container *container.Contai
|
||||||
if _, ok := container.NetworkSettings.Networks[networkName]; ok {
|
if _, ok := container.NetworkSettings.Networks[networkName]; ok {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if nwConfig, ok := container.NetworkSettings.Networks[n.ID()]; ok {
|
|
||||||
container.NetworkSettings.Networks[networkName] = nwConfig
|
if n != nil {
|
||||||
delete(container.NetworkSettings.Networks, n.ID())
|
if nwConfig, ok := container.NetworkSettings.Networks[n.ID()]; ok {
|
||||||
return nil
|
container.NetworkSettings.Networks[networkName] = nwConfig
|
||||||
|
delete(container.NetworkSettings.Networks, n.ID())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -414,16 +492,27 @@ func (daemon *Daemon) allocateNetwork(container *container.Container) error {
|
||||||
// on first network connecting.
|
// on first network connecting.
|
||||||
defaultNetName := runconfig.DefaultDaemonNetworkMode().NetworkName()
|
defaultNetName := runconfig.DefaultDaemonNetworkMode().NetworkName()
|
||||||
if nConf, ok := container.NetworkSettings.Networks[defaultNetName]; ok {
|
if nConf, ok := container.NetworkSettings.Networks[defaultNetName]; ok {
|
||||||
if err := daemon.connectToNetwork(container, defaultNetName, nConf, updateSettings); err != nil {
|
if err := daemon.connectToNetwork(container, defaultNetName, nConf.EndpointSettings, updateSettings); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
for n, nConf := range container.NetworkSettings.Networks {
|
var (
|
||||||
|
networks []string
|
||||||
|
epConfigs []*network.EndpointSettings
|
||||||
|
)
|
||||||
|
|
||||||
|
for n, epConf := range container.NetworkSettings.Networks {
|
||||||
if n == defaultNetName {
|
if n == defaultNetName {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if err := daemon.connectToNetwork(container, n, nConf, updateSettings); err != nil {
|
|
||||||
|
networks = append(networks, n)
|
||||||
|
epConfigs = append(epConfigs, epConf)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, epConf := range epConfigs {
|
||||||
|
if err := daemon.connectToNetwork(container, networks[i], epConf.EndpointSettings, updateSettings); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -488,7 +577,7 @@ func validateNetworkingConfig(n libnetwork.Network, epConfig *networktypes.Endpo
|
||||||
}
|
}
|
||||||
|
|
||||||
// cleanOperationalData resets the operational data from the passed endpoint settings
|
// cleanOperationalData resets the operational data from the passed endpoint settings
|
||||||
func cleanOperationalData(es *networktypes.EndpointSettings) {
|
func cleanOperationalData(es *network.EndpointSettings) {
|
||||||
es.EndpointID = ""
|
es.EndpointID = ""
|
||||||
es.Gateway = ""
|
es.Gateway = ""
|
||||||
es.IPAddress = ""
|
es.IPAddress = ""
|
||||||
|
@ -497,25 +586,18 @@ func cleanOperationalData(es *networktypes.EndpointSettings) {
|
||||||
es.GlobalIPv6Address = ""
|
es.GlobalIPv6Address = ""
|
||||||
es.GlobalIPv6PrefixLen = 0
|
es.GlobalIPv6PrefixLen = 0
|
||||||
es.MacAddress = ""
|
es.MacAddress = ""
|
||||||
|
if es.IPAMOperational {
|
||||||
|
es.IPAMConfig = nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (daemon *Daemon) updateNetworkConfig(container *container.Container, idOrName string, endpointConfig *networktypes.EndpointSettings, updateSettings bool) (libnetwork.Network, error) {
|
func (daemon *Daemon) updateNetworkConfig(container *container.Container, n libnetwork.Network, endpointConfig *networktypes.EndpointSettings, updateSettings bool) error {
|
||||||
if container.HostConfig.NetworkMode.IsContainer() {
|
if !containertypes.NetworkMode(n.Name()).IsUserDefined() {
|
||||||
return nil, runconfig.ErrConflictSharedNetwork
|
|
||||||
}
|
|
||||||
|
|
||||||
if containertypes.NetworkMode(idOrName).IsBridge() &&
|
|
||||||
daemon.configStore.DisableBridge {
|
|
||||||
container.Config.NetworkDisabled = true
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if !containertypes.NetworkMode(idOrName).IsUserDefined() {
|
|
||||||
if hasUserDefinedIPAddress(endpointConfig) && !enableIPOnPredefinedNetwork() {
|
if hasUserDefinedIPAddress(endpointConfig) && !enableIPOnPredefinedNetwork() {
|
||||||
return nil, runconfig.ErrUnsupportedNetworkAndIP
|
return runconfig.ErrUnsupportedNetworkAndIP
|
||||||
}
|
}
|
||||||
if endpointConfig != nil && len(endpointConfig.Aliases) > 0 {
|
if endpointConfig != nil && len(endpointConfig.Aliases) > 0 {
|
||||||
return nil, runconfig.ErrUnsupportedNetworkAndAlias
|
return runconfig.ErrUnsupportedNetworkAndAlias
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
addShortID := true
|
addShortID := true
|
||||||
|
@ -531,28 +613,34 @@ func (daemon *Daemon) updateNetworkConfig(container *container.Container, idOrNa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
n, err := daemon.FindNetwork(idOrName)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := validateNetworkingConfig(n, endpointConfig); err != nil {
|
if err := validateNetworkingConfig(n, endpointConfig); err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if updateSettings {
|
if updateSettings {
|
||||||
if err := daemon.updateNetworkSettings(container, n); err != nil {
|
if err := daemon.updateNetworkSettings(container, n, endpointConfig); err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return n, nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (daemon *Daemon) connectToNetwork(container *container.Container, idOrName string, endpointConfig *networktypes.EndpointSettings, updateSettings bool) (err error) {
|
func (daemon *Daemon) connectToNetwork(container *container.Container, idOrName string, endpointConfig *networktypes.EndpointSettings, updateSettings bool) (err error) {
|
||||||
|
if container.HostConfig.NetworkMode.IsContainer() {
|
||||||
|
return runconfig.ErrConflictSharedNetwork
|
||||||
|
}
|
||||||
|
|
||||||
|
if containertypes.NetworkMode(idOrName).IsBridge() &&
|
||||||
|
daemon.configStore.DisableBridge {
|
||||||
|
container.Config.NetworkDisabled = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
if endpointConfig == nil {
|
if endpointConfig == nil {
|
||||||
endpointConfig = &networktypes.EndpointSettings{}
|
endpointConfig = &networktypes.EndpointSettings{}
|
||||||
}
|
}
|
||||||
n, err := daemon.updateNetworkConfig(container, idOrName, endpointConfig, updateSettings)
|
|
||||||
|
n, config, err := daemon.findAndAttachNetwork(container, idOrName, endpointConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -560,6 +648,25 @@ func (daemon *Daemon) connectToNetwork(container *container.Container, idOrName
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var operIPAM bool
|
||||||
|
if config != nil {
|
||||||
|
if epConfig, ok := config.EndpointsConfig[n.Name()]; ok {
|
||||||
|
if endpointConfig.IPAMConfig == nil ||
|
||||||
|
(endpointConfig.IPAMConfig.IPv4Address == "" &&
|
||||||
|
endpointConfig.IPAMConfig.IPv6Address == "" &&
|
||||||
|
len(endpointConfig.IPAMConfig.LinkLocalIPs) == 0) {
|
||||||
|
operIPAM = true
|
||||||
|
}
|
||||||
|
|
||||||
|
endpointConfig = epConfig
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = daemon.updateNetworkConfig(container, n, endpointConfig, updateSettings)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
controller := daemon.netController
|
controller := daemon.netController
|
||||||
|
|
||||||
sb := daemon.getNetworkSandbox(container)
|
sb := daemon.getNetworkSandbox(container)
|
||||||
|
@ -580,7 +687,13 @@ func (daemon *Daemon) connectToNetwork(container *container.Container, idOrName
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
container.NetworkSettings.Networks[n.Name()] = endpointConfig
|
container.NetworkSettings.Networks[n.Name()] = &network.EndpointSettings{
|
||||||
|
EndpointSettings: endpointConfig,
|
||||||
|
IPAMOperational: operIPAM,
|
||||||
|
}
|
||||||
|
if _, ok := container.NetworkSettings.Networks[n.ID()]; ok {
|
||||||
|
delete(container.NetworkSettings.Networks, n.ID())
|
||||||
|
}
|
||||||
|
|
||||||
if err := daemon.updateEndpointNetworkSettings(container, n, ep); err != nil {
|
if err := daemon.updateEndpointNetworkSettings(container, n, ep); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -632,7 +745,7 @@ func (daemon *Daemon) ForceEndpointDelete(name string, networkName string) error
|
||||||
return ep.Delete(true)
|
return ep.Delete(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func disconnectFromNetwork(container *container.Container, n libnetwork.Network, force bool) error {
|
func (daemon *Daemon) disconnectFromNetwork(container *container.Container, n libnetwork.Network, force bool) error {
|
||||||
var (
|
var (
|
||||||
ep libnetwork.Endpoint
|
ep libnetwork.Endpoint
|
||||||
sbox libnetwork.Sandbox
|
sbox libnetwork.Sandbox
|
||||||
|
@ -678,6 +791,13 @@ func disconnectFromNetwork(container *container.Container, n libnetwork.Network,
|
||||||
}
|
}
|
||||||
|
|
||||||
delete(container.NetworkSettings.Networks, n.Name())
|
delete(container.NetworkSettings.Networks, n.Name())
|
||||||
|
|
||||||
|
if daemon.clusterProvider != nil && n.Info().Dynamic() && !container.Managed {
|
||||||
|
if err := daemon.clusterProvider.DetachNetwork(n.Name(), container.ID); err != nil {
|
||||||
|
logrus.Warnf("error detaching from network %s: %v", n, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -751,6 +871,11 @@ func (daemon *Daemon) releaseNetwork(container *container.Container) {
|
||||||
if nw, err := daemon.FindNetwork(n); err == nil {
|
if nw, err := daemon.FindNetwork(n); err == nil {
|
||||||
networks = append(networks, nw)
|
networks = append(networks, nw)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if epSettings.EndpointSettings == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
cleanOperationalData(epSettings)
|
cleanOperationalData(epSettings)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -765,6 +890,12 @@ func (daemon *Daemon) releaseNetwork(container *container.Container) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, nw := range networks {
|
for _, nw := range networks {
|
||||||
|
if daemon.clusterProvider != nil && nw.Info().Dynamic() && !container.Managed {
|
||||||
|
if err := daemon.clusterProvider.DetachNetwork(nw.Name(), container.ID); err != nil {
|
||||||
|
logrus.Warnf("error detaching from network %s: %v", nw.Name(), err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
attributes := map[string]string{
|
attributes := map[string]string{
|
||||||
"container": container.ID,
|
"container": container.ID,
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ import (
|
||||||
networktypes "github.com/docker/docker/api/types/network"
|
networktypes "github.com/docker/docker/api/types/network"
|
||||||
"github.com/docker/docker/container"
|
"github.com/docker/docker/container"
|
||||||
"github.com/docker/docker/daemon/links"
|
"github.com/docker/docker/daemon/links"
|
||||||
|
"github.com/docker/docker/daemon/network"
|
||||||
"github.com/docker/docker/pkg/fileutils"
|
"github.com/docker/docker/pkg/fileutils"
|
||||||
"github.com/docker/docker/pkg/idtools"
|
"github.com/docker/docker/pkg/idtools"
|
||||||
"github.com/docker/docker/pkg/mount"
|
"github.com/docker/docker/pkg/mount"
|
||||||
|
@ -35,7 +36,7 @@ func (daemon *Daemon) setupLinkedContainers(container *container.Container) ([]s
|
||||||
children := daemon.children(container)
|
children := daemon.children(container)
|
||||||
|
|
||||||
bridgeSettings := container.NetworkSettings.Networks[runconfig.DefaultDaemonNetworkMode().NetworkName()]
|
bridgeSettings := container.NetworkSettings.Networks[runconfig.DefaultDaemonNetworkMode().NetworkName()]
|
||||||
if bridgeSettings == nil {
|
if bridgeSettings == nil || bridgeSettings.EndpointSettings == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,7 +46,7 @@ func (daemon *Daemon) setupLinkedContainers(container *container.Container) ([]s
|
||||||
}
|
}
|
||||||
|
|
||||||
childBridgeSettings := child.NetworkSettings.Networks[runconfig.DefaultDaemonNetworkMode().NetworkName()]
|
childBridgeSettings := child.NetworkSettings.Networks[runconfig.DefaultDaemonNetworkMode().NetworkName()]
|
||||||
if childBridgeSettings == nil {
|
if childBridgeSettings == nil || childBridgeSettings.EndpointSettings == nil {
|
||||||
return nil, fmt.Errorf("container %s not attached to default bridge network", child.ID)
|
return nil, fmt.Errorf("container %s not attached to default bridge network", child.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,10 +108,17 @@ func (daemon *Daemon) ConnectToNetwork(container *container.Container, idOrName
|
||||||
if container.RemovalInProgress || container.Dead {
|
if container.RemovalInProgress || container.Dead {
|
||||||
return errRemovalContainer(container.ID)
|
return errRemovalContainer(container.ID)
|
||||||
}
|
}
|
||||||
if _, err := daemon.updateNetworkConfig(container, idOrName, endpointConfig, true); err != nil {
|
|
||||||
return err
|
n, err := daemon.FindNetwork(idOrName)
|
||||||
|
if err == nil && n != nil {
|
||||||
|
if err := daemon.updateNetworkConfig(container, n, endpointConfig, true); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
container.NetworkSettings.Networks[idOrName] = &network.EndpointSettings{
|
||||||
|
EndpointSettings: endpointConfig,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
container.NetworkSettings.Networks[idOrName] = endpointConfig
|
|
||||||
} else {
|
} else {
|
||||||
if err := daemon.connectToNetwork(container, idOrName, endpointConfig, true); err != nil {
|
if err := daemon.connectToNetwork(container, idOrName, endpointConfig, true); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -143,7 +151,7 @@ func (daemon *Daemon) DisconnectFromNetwork(container *container.Container, netw
|
||||||
return runconfig.ErrConflictHostNetwork
|
return runconfig.ErrConflictHostNetwork
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := disconnectFromNetwork(container, n, false); err != nil {
|
if err := daemon.disconnectFromNetwork(container, n, false); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -252,7 +252,7 @@ func (daemon *Daemon) verifyNetworkingConfig(nwConfig *networktypes.NetworkingCo
|
||||||
}
|
}
|
||||||
if len(nwConfig.EndpointsConfig) == 1 {
|
if len(nwConfig.EndpointsConfig) == 1 {
|
||||||
for _, v := range nwConfig.EndpointsConfig {
|
for _, v := range nwConfig.EndpointsConfig {
|
||||||
if v.IPAMConfig != nil {
|
if v != nil && v.IPAMConfig != nil {
|
||||||
if v.IPAMConfig.IPv4Address != "" && net.ParseIP(v.IPAMConfig.IPv4Address).To4() == nil {
|
if v.IPAMConfig.IPv4Address != "" && net.ParseIP(v.IPAMConfig.IPv4Address).To4() == nil {
|
||||||
return errors.NewBadRequestError(fmt.Errorf("invalid IPv4 address: %s", v.IPAMConfig.IPv4Address))
|
return errors.NewBadRequestError(fmt.Errorf("invalid IPv4 address: %s", v.IPAMConfig.IPv4Address))
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,6 +42,13 @@ func (daemon *Daemon) ContainerInspectCurrent(name string, size bool) (*types.Co
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
apiNetworks := make(map[string]*networktypes.EndpointSettings)
|
||||||
|
for name, epConf := range container.NetworkSettings.Networks {
|
||||||
|
if epConf.EndpointSettings != nil {
|
||||||
|
apiNetworks[name] = epConf.EndpointSettings
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mountPoints := addMountPoints(container)
|
mountPoints := addMountPoints(container)
|
||||||
networkSettings := &types.NetworkSettings{
|
networkSettings := &types.NetworkSettings{
|
||||||
NetworkSettingsBase: types.NetworkSettingsBase{
|
NetworkSettingsBase: types.NetworkSettingsBase{
|
||||||
|
@ -56,7 +63,7 @@ func (daemon *Daemon) ContainerInspectCurrent(name string, size bool) (*types.Co
|
||||||
SecondaryIPv6Addresses: container.NetworkSettings.SecondaryIPv6Addresses,
|
SecondaryIPv6Addresses: container.NetworkSettings.SecondaryIPv6Addresses,
|
||||||
},
|
},
|
||||||
DefaultNetworkSettings: daemon.getDefaultNetworkSettings(container.NetworkSettings.Networks),
|
DefaultNetworkSettings: daemon.getDefaultNetworkSettings(container.NetworkSettings.Networks),
|
||||||
Networks: container.NetworkSettings.Networks,
|
Networks: apiNetworks,
|
||||||
}
|
}
|
||||||
|
|
||||||
return &types.ContainerJSON{
|
return &types.ContainerJSON{
|
||||||
|
@ -236,10 +243,10 @@ func (daemon *Daemon) getBackwardsCompatibleNetworkSettings(settings *network.Se
|
||||||
|
|
||||||
// getDefaultNetworkSettings creates the deprecated structure that holds the information
|
// getDefaultNetworkSettings creates the deprecated structure that holds the information
|
||||||
// about the bridge network for a container.
|
// about the bridge network for a container.
|
||||||
func (daemon *Daemon) getDefaultNetworkSettings(networks map[string]*networktypes.EndpointSettings) types.DefaultNetworkSettings {
|
func (daemon *Daemon) getDefaultNetworkSettings(networks map[string]*network.EndpointSettings) types.DefaultNetworkSettings {
|
||||||
var settings types.DefaultNetworkSettings
|
var settings types.DefaultNetworkSettings
|
||||||
|
|
||||||
if defaultNetwork, ok := networks["bridge"]; ok {
|
if defaultNetwork, ok := networks["bridge"]; ok && defaultNetwork.EndpointSettings != nil {
|
||||||
settings.EndpointID = defaultNetwork.EndpointID
|
settings.EndpointID = defaultNetwork.EndpointID
|
||||||
settings.Gateway = defaultNetwork.Gateway
|
settings.Gateway = defaultNetwork.Gateway
|
||||||
settings.GlobalIPv6Address = defaultNetwork.GlobalIPv6Address
|
settings.GlobalIPv6Address = defaultNetwork.GlobalIPv6Address
|
||||||
|
|
|
@ -400,6 +400,9 @@ func includeContainerInList(container *container.Container, ctx *listContext) it
|
||||||
return networkExist
|
return networkExist
|
||||||
}
|
}
|
||||||
for _, nw := range container.NetworkSettings.Networks {
|
for _, nw := range container.NetworkSettings.Networks {
|
||||||
|
if nw.EndpointSettings == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
if nw.NetworkID == value {
|
if nw.NetworkID == value {
|
||||||
return networkExist
|
return networkExist
|
||||||
}
|
}
|
||||||
|
@ -460,7 +463,7 @@ func (daemon *Daemon) transformContainer(container *container.Container, ctx *li
|
||||||
// copy networks to avoid races
|
// copy networks to avoid races
|
||||||
networks := make(map[string]*networktypes.EndpointSettings)
|
networks := make(map[string]*networktypes.EndpointSettings)
|
||||||
for name, network := range container.NetworkSettings.Networks {
|
for name, network := range container.NetworkSettings.Networks {
|
||||||
if network == nil {
|
if network == nil || network.EndpointSettings == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
networks[name] = &networktypes.EndpointSettings{
|
networks[name] = &networktypes.EndpointSettings{
|
||||||
|
|
|
@ -14,6 +14,7 @@ import (
|
||||||
"github.com/docker/docker/runconfig"
|
"github.com/docker/docker/runconfig"
|
||||||
"github.com/docker/libnetwork"
|
"github.com/docker/libnetwork"
|
||||||
networktypes "github.com/docker/libnetwork/types"
|
networktypes "github.com/docker/libnetwork/types"
|
||||||
|
"golang.org/x/net/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NetworkControllerEnabled checks if the networking stack is enabled.
|
// NetworkControllerEnabled checks if the networking stack is enabled.
|
||||||
|
@ -186,6 +187,29 @@ func (daemon *Daemon) SetNetworkBootstrapKeys(keys []*networktypes.EncryptionKey
|
||||||
return daemon.netController.SetKeys(keys)
|
return daemon.netController.SetKeys(keys)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
|
||||||
// CreateManagedNetwork creates an agent network.
|
// CreateManagedNetwork creates an agent network.
|
||||||
func (daemon *Daemon) CreateManagedNetwork(create clustertypes.NetworkCreateRequest) error {
|
func (daemon *Daemon) CreateManagedNetwork(create clustertypes.NetworkCreateRequest) error {
|
||||||
_, err := daemon.createNetwork(create.NetworkCreateRequest, create.ID, true)
|
_, err := daemon.createNetwork(create.NetworkCreateRequest, create.ID, true)
|
||||||
|
|
|
@ -14,7 +14,7 @@ type Settings struct {
|
||||||
HairpinMode bool
|
HairpinMode bool
|
||||||
LinkLocalIPv6Address string
|
LinkLocalIPv6Address string
|
||||||
LinkLocalIPv6PrefixLen int
|
LinkLocalIPv6PrefixLen int
|
||||||
Networks map[string]*networktypes.EndpointSettings
|
Networks map[string]*EndpointSettings
|
||||||
Service *clustertypes.ServiceConfig
|
Service *clustertypes.ServiceConfig
|
||||||
Ports nat.PortMap
|
Ports nat.PortMap
|
||||||
SandboxKey string
|
SandboxKey string
|
||||||
|
@ -22,3 +22,11 @@ type Settings struct {
|
||||||
SecondaryIPv6Addresses []networktypes.Address
|
SecondaryIPv6Addresses []networktypes.Address
|
||||||
IsAnonymousEndpoint bool
|
IsAnonymousEndpoint bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EndpointSettings is a package local wrapper for
|
||||||
|
// networktypes.EndpointSettings which stores Endpoint state that
|
||||||
|
// needs to be persisted to disk but not exposed in the api.
|
||||||
|
type EndpointSettings struct {
|
||||||
|
*networktypes.EndpointSettings
|
||||||
|
IPAMOperational bool
|
||||||
|
}
|
||||||
|
|
|
@ -298,6 +298,8 @@ func (s *DockerSwarmSuite) TearDownTest(c *check.C) {
|
||||||
if err := os.RemoveAll(walDir); err != nil {
|
if err := os.RemoveAll(walDir); err != nil {
|
||||||
c.Logf("error removing %v: %v", walDir, err)
|
c.Logf("error removing %v: %v", walDir, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cleanupExecRoot(c, d.execRoot)
|
||||||
}
|
}
|
||||||
s.daemons = nil
|
s.daemons = nil
|
||||||
s.daemonsLock.Unlock()
|
s.daemonsLock.Unlock()
|
||||||
|
|
|
@ -2,7 +2,29 @@
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import "syscall"
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/go-check/check"
|
||||||
|
)
|
||||||
|
|
||||||
|
func cleanupExecRoot(c *check.C, execRoot string) {
|
||||||
|
// Cleanup network namespaces in the exec root of this
|
||||||
|
// daemon because this exec root is specific to this
|
||||||
|
// daemon instance and has no chance of getting
|
||||||
|
// cleaned up when a new daemon is instantiated with a
|
||||||
|
// new exec root.
|
||||||
|
netnsPath := filepath.Join(execRoot, "netns")
|
||||||
|
filepath.Walk(netnsPath, func(path string, info os.FileInfo, err error) error {
|
||||||
|
if err := syscall.Unmount(path, syscall.MNT_FORCE); err != nil {
|
||||||
|
c.Logf("unmount of %s failed: %v", path, err)
|
||||||
|
}
|
||||||
|
os.Remove(path)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func signalDaemonDump(pid int) {
|
func signalDaemonDump(pid int) {
|
||||||
syscall.Kill(pid, syscall.SIGQUIT)
|
syscall.Kill(pid, syscall.SIGQUIT)
|
||||||
|
|
|
@ -5,6 +5,8 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"syscall"
|
"syscall"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/go-check/check"
|
||||||
)
|
)
|
||||||
|
|
||||||
func openEvent(desiredAccess uint32, inheritHandle bool, name string, proc *syscall.LazyProc) (handle syscall.Handle, err error) {
|
func openEvent(desiredAccess uint32, inheritHandle bool, name string, proc *syscall.LazyProc) (handle syscall.Handle, err error) {
|
||||||
|
@ -45,3 +47,6 @@ func signalDaemonDump(pid int) {
|
||||||
func signalDaemonReload(pid int) error {
|
func signalDaemonReload(pid int) error {
|
||||||
return fmt.Errorf("daemon reload not supported")
|
return fmt.Errorf("daemon reload not supported")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func cleanupExecRoot(c *check.C, execRoot string) {
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue