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
|
||||
internal bool
|
||||
ipv6 bool
|
||||
attachable bool
|
||||
|
||||
ipamDriver 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.BoolVar(&opts.internal, "internal", false, "Restrict external access to the network")
|
||||
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.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,
|
||||
Internal: opts.internal,
|
||||
EnableIPv6: opts.ipv6,
|
||||
Attachable: opts.attachable,
|
||||
Labels: runconfigopts.ConvertKVStringsToMap(opts.labels),
|
||||
}
|
||||
|
||||
|
|
|
@ -451,6 +451,7 @@ func (opts *serviceOptions) ToService() (swarm.ServiceSpec, error) {
|
|||
Mounts: opts.mounts.Value(),
|
||||
StopGracePeriod: opts.stopGrace.Value(),
|
||||
},
|
||||
Networks: convertNetworks(opts.networks),
|
||||
Resources: opts.resources.ToResourceRequirements(),
|
||||
RestartPolicy: opts.restartPolicy.ToRestartPolicy(),
|
||||
Placement: &swarm.Placement{
|
||||
|
@ -458,13 +459,13 @@ func (opts *serviceOptions) ToService() (swarm.ServiceSpec, error) {
|
|||
},
|
||||
LogDriver: opts.logDriver.toLogDriver(),
|
||||
},
|
||||
Mode: swarm.ServiceMode{},
|
||||
Networks: convertNetworks(opts.networks),
|
||||
Mode: swarm.ServiceMode{},
|
||||
UpdateConfig: &swarm.UpdateConfig{
|
||||
Parallelism: opts.update.parallelism,
|
||||
Delay: opts.update.delay,
|
||||
FailureAction: opts.update.onFailure,
|
||||
},
|
||||
Networks: convertNetworks(opts.networks),
|
||||
EndpointSpec: opts.endpoint.ToEndpointSpec(),
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@ package network
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
@ -11,7 +10,6 @@ import (
|
|||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/api/types/network"
|
||||
"github.com/docker/docker/errors"
|
||||
"github.com/docker/libnetwork"
|
||||
)
|
||||
|
||||
|
@ -116,17 +114,7 @@ func (n *networkRouter) postNetworkConnect(ctx context.Context, w http.ResponseW
|
|||
return err
|
||||
}
|
||||
|
||||
nw, err := n.backend.FindNetwork(vars["id"])
|
||||
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)
|
||||
return n.backend.ConnectContainerToNetwork(connect.Container, vars["id"], connect.EndpointConfig)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
|
|
|
@ -700,7 +700,9 @@ func (container *Container) BuildEndpointInfo(n libnetwork.Network, ep libnetwor
|
|||
}
|
||||
|
||||
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()].EndpointID = ep.ID()
|
||||
|
|
|
@ -16,6 +16,7 @@ import (
|
|||
"github.com/Sirupsen/logrus"
|
||||
apitypes "github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/api/types/network"
|
||||
types "github.com/docker/docker/api/types/swarm"
|
||||
"github.com/docker/docker/daemon/cluster/convert"
|
||||
executorpkg "github.com/docker/docker/daemon/cluster/executor"
|
||||
|
@ -126,6 +127,18 @@ type Cluster struct {
|
|||
stop bool
|
||||
err error
|
||||
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 {
|
||||
|
@ -154,6 +167,7 @@ func New(config Config) (*Cluster, error) {
|
|||
config: config,
|
||||
configEvent: make(chan struct{}, 10),
|
||||
runtimeRoot: config.RuntimeRoot,
|
||||
attachers: make(map[string]*attacher),
|
||||
}
|
||||
|
||||
st, err := c.loadState()
|
||||
|
@ -1212,6 +1226,120 @@ func (c *Cluster) GetNetworks() ([]apitypes.NetworkResource, error) {
|
|||
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.
|
||||
func (c *Cluster) CreateNetwork(s apitypes.NetworkCreateRequest) (string, error) {
|
||||
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 {
|
||||
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)
|
||||
if err != nil {
|
||||
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
|
||||
}
|
||||
s.Networks[i].Target = apiNetwork.ID
|
||||
networks[i].Target = apiNetwork.ID
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ func networkFromGRPC(n *swarmapi.Network) types.Network {
|
|||
Spec: types.NetworkSpec{
|
||||
IPv6Enabled: n.Spec.Ipv6Enabled,
|
||||
Internal: n.Spec.Internal,
|
||||
Attachable: n.Spec.Attachable,
|
||||
IPAMOptions: ipamFromGRPC(n.Spec.IPAM),
|
||||
},
|
||||
IPAMOptions: ipamFromGRPC(n.IPAM),
|
||||
|
@ -155,6 +156,7 @@ func BasicNetworkFromGRPC(n swarmapi.Network) basictypes.NetworkResource {
|
|||
EnableIPv6: spec.Ipv6Enabled,
|
||||
IPAM: ipam,
|
||||
Internal: spec.Internal,
|
||||
Attachable: spec.Attachable,
|
||||
Labels: n.Spec.Annotations.Labels,
|
||||
}
|
||||
|
||||
|
@ -179,6 +181,7 @@ func BasicNetworkCreateToGRPC(create basictypes.NetworkCreateRequest) swarmapi.N
|
|||
},
|
||||
Ipv6Enabled: create.EnableIPv6,
|
||||
Internal: create.Internal,
|
||||
Attachable: create.Attachable,
|
||||
}
|
||||
if create.IPAM != nil {
|
||||
ns.IPAM = &swarmapi.IPAMOptions{
|
||||
|
|
|
@ -15,10 +15,16 @@ func ServiceFromGRPC(s swarmapi.Service) types.Service {
|
|||
spec := s.Spec
|
||||
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 {
|
||||
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{
|
||||
ID: s.ID,
|
||||
|
||||
|
@ -29,9 +35,10 @@ func ServiceFromGRPC(s swarmapi.Service) types.Service {
|
|||
RestartPolicy: restartPolicyFromGRPC(s.Spec.Task.Restart),
|
||||
Placement: placementFromGRPC(s.Spec.Task.Placement),
|
||||
LogDriver: driverFromGRPC(s.Spec.Task.LogDriver),
|
||||
Networks: taskNetworks,
|
||||
},
|
||||
|
||||
Networks: networks,
|
||||
Networks: serviceNetworks,
|
||||
EndpointSpec: endpointSpecFromGRPC(s.Spec.Endpoint),
|
||||
},
|
||||
Endpoint: endpointFromGRPC(s.Endpoint),
|
||||
|
@ -99,9 +106,14 @@ func ServiceSpecToGRPC(s types.ServiceSpec) (swarmapi.ServiceSpec, error) {
|
|||
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 {
|
||||
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{
|
||||
|
@ -112,8 +124,9 @@ func ServiceSpecToGRPC(s types.ServiceSpec) (swarmapi.ServiceSpec, error) {
|
|||
Task: swarmapi.TaskSpec{
|
||||
Resources: resourcesToGRPC(s.TaskTemplate.Resources),
|
||||
LogDriver: driverToGRPC(s.TaskTemplate.LogDriver),
|
||||
Networks: taskNetworks,
|
||||
},
|
||||
Networks: networks,
|
||||
Networks: serviceNetworks,
|
||||
}
|
||||
|
||||
containerSpec, err := containerToGRPC(s.TaskTemplate.ContainerSpec)
|
||||
|
|
|
@ -12,6 +12,11 @@ import (
|
|||
func TaskFromGRPC(t swarmapi.Task) types.Task {
|
||||
containerConfig := t.Spec.Runtime.(*swarmapi.TaskSpec_Container).Container
|
||||
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{
|
||||
ID: t.ID,
|
||||
ServiceID: t.ServiceID,
|
||||
|
@ -23,6 +28,7 @@ func TaskFromGRPC(t swarmapi.Task) types.Task {
|
|||
RestartPolicy: restartPolicyFromGRPC(t.Spec.Restart),
|
||||
Placement: placementFromGRPC(t.Spec.Placement),
|
||||
LogDriver: driverFromGRPC(t.Spec.LogDriver),
|
||||
Networks: networks,
|
||||
},
|
||||
Status: types.TaskStatus{
|
||||
State: types.TaskState(strings.ToLower(t.Status.State.String())),
|
||||
|
|
|
@ -40,4 +40,6 @@ type Backend interface {
|
|||
IsSwarmCompatible() error
|
||||
SubscribeToEvents(since, until time.Time, filter filters.Args) ([]events.Message, 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
|
||||
}
|
||||
|
||||
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 {
|
||||
var cr types.ContainerCreateResponse
|
||||
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 {
|
||||
return c.backend.ContainerWaitWithContext(ctx, c.container.name())
|
||||
return c.backend.ContainerWaitWithContext(ctx, c.container.nameOrID())
|
||||
}
|
||||
|
||||
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 {
|
||||
container := t.Spec.GetContainer()
|
||||
if container == nil {
|
||||
if t.Spec.GetContainer() == nil && t.Spec.GetAttachment() == nil {
|
||||
return exec.ErrRuntimeUnsupported
|
||||
}
|
||||
|
||||
if container.Image == "" {
|
||||
return ErrImageRequired
|
||||
}
|
||||
container := t.Spec.GetContainer()
|
||||
if container != nil {
|
||||
if container.Image == "" {
|
||||
return ErrImageRequired
|
||||
}
|
||||
|
||||
if err := validateMounts(container.Mounts); err != nil {
|
||||
return err
|
||||
if err := validateMounts(container.Mounts); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// index the networks by name
|
||||
|
@ -67,6 +69,19 @@ func (c *containerConfig) setTask(t *api.Task) error {
|
|||
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 {
|
||||
return c.task.Endpoint
|
||||
}
|
||||
|
@ -75,6 +90,14 @@ func (c *containerConfig) spec() *api.ContainerSpec {
|
|||
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 {
|
||||
if c.task.Annotations.Name != "" {
|
||||
// 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.
|
||||
func (c *containerConfig) createNetworkingConfig() *network.NetworkingConfig {
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -392,6 +415,7 @@ func getEndpointConfig(na *api.NetworkAttachment) *network.EndpointSettings {
|
|||
}
|
||||
|
||||
return &network.EndpointSettings{
|
||||
NetworkID: na.Network.ID,
|
||||
IPAMConfig: &network.EndpointIPAMConfig{
|
||||
IPv4Address: ipv4,
|
||||
IPv6Address: ipv6,
|
||||
|
|
|
@ -121,6 +121,10 @@ func (e *executor) Configure(ctx context.Context, node *api.Node) error {
|
|||
|
||||
// Controller returns a docker container runner.
|
||||
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)
|
||||
if err != nil {
|
||||
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
|
||||
// Legacy Link is only supported by docker run --link
|
||||
bridgeSettings, ok := container.NetworkSettings.Networks[defaultNetName]
|
||||
if !ok {
|
||||
if !ok || bridgeSettings.EndpointSettings == nil {
|
||||
return sboxOptions, nil
|
||||
}
|
||||
|
||||
|
@ -238,9 +238,9 @@ func (daemon *Daemon) buildSandboxOptions(container *container.Container) ([]lib
|
|||
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 {
|
||||
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() {
|
||||
|
@ -268,7 +268,9 @@ func (daemon *Daemon) updateNetworkSettings(container *container.Container, n li
|
|||
}
|
||||
|
||||
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
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
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
|
||||
func (daemon *Daemon) updateContainerNetworkSettings(container *container.Container, endpointsConfig map[string]*networktypes.EndpointSettings) error {
|
||||
var (
|
||||
n libnetwork.Network
|
||||
err error
|
||||
)
|
||||
var n libnetwork.Network
|
||||
|
||||
mode := container.HostConfig.NetworkMode
|
||||
if container.Config.NetworkDisabled || mode.IsContainer() {
|
||||
|
@ -347,26 +400,48 @@ func (daemon *Daemon) updateContainerNetworkSettings(container *container.Contai
|
|||
if mode.IsDefault() {
|
||||
networkName = daemon.netController.Config().Daemon.DefaultNetwork
|
||||
}
|
||||
|
||||
if mode.IsUserDefined() {
|
||||
var err error
|
||||
|
||||
n, err = daemon.FindNetwork(networkName)
|
||||
if err != nil {
|
||||
return err
|
||||
if err == nil {
|
||||
networkName = n.Name()
|
||||
}
|
||||
if !container.Managed && n.Info().Dynamic() {
|
||||
return errClusterNetworkOnRun(networkName)
|
||||
}
|
||||
networkName = n.Name()
|
||||
}
|
||||
|
||||
if container.NetworkSettings == nil {
|
||||
container.NetworkSettings = &network.Settings{}
|
||||
}
|
||||
|
||||
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 {
|
||||
container.NetworkSettings.Networks = make(map[string]*networktypes.EndpointSettings)
|
||||
container.NetworkSettings.Networks[networkName] = new(networktypes.EndpointSettings)
|
||||
container.NetworkSettings.Networks = make(map[string]*network.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() {
|
||||
return nil
|
||||
}
|
||||
|
@ -374,10 +449,13 @@ func (daemon *Daemon) updateContainerNetworkSettings(container *container.Contai
|
|||
if _, ok := container.NetworkSettings.Networks[networkName]; ok {
|
||||
return nil
|
||||
}
|
||||
if nwConfig, ok := container.NetworkSettings.Networks[n.ID()]; ok {
|
||||
container.NetworkSettings.Networks[networkName] = nwConfig
|
||||
delete(container.NetworkSettings.Networks, n.ID())
|
||||
return nil
|
||||
|
||||
if n != nil {
|
||||
if nwConfig, ok := container.NetworkSettings.Networks[n.ID()]; ok {
|
||||
container.NetworkSettings.Networks[networkName] = nwConfig
|
||||
delete(container.NetworkSettings.Networks, n.ID())
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -414,16 +492,27 @@ func (daemon *Daemon) allocateNetwork(container *container.Container) error {
|
|||
// on first network connecting.
|
||||
defaultNetName := runconfig.DefaultDaemonNetworkMode().NetworkName()
|
||||
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
|
||||
}
|
||||
|
||||
}
|
||||
for n, nConf := range container.NetworkSettings.Networks {
|
||||
var (
|
||||
networks []string
|
||||
epConfigs []*network.EndpointSettings
|
||||
)
|
||||
|
||||
for n, epConf := range container.NetworkSettings.Networks {
|
||||
if n == defaultNetName {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
@ -488,7 +577,7 @@ func validateNetworkingConfig(n libnetwork.Network, epConfig *networktypes.Endpo
|
|||
}
|
||||
|
||||
// cleanOperationalData resets the operational data from the passed endpoint settings
|
||||
func cleanOperationalData(es *networktypes.EndpointSettings) {
|
||||
func cleanOperationalData(es *network.EndpointSettings) {
|
||||
es.EndpointID = ""
|
||||
es.Gateway = ""
|
||||
es.IPAddress = ""
|
||||
|
@ -497,25 +586,18 @@ func cleanOperationalData(es *networktypes.EndpointSettings) {
|
|||
es.GlobalIPv6Address = ""
|
||||
es.GlobalIPv6PrefixLen = 0
|
||||
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) {
|
||||
if container.HostConfig.NetworkMode.IsContainer() {
|
||||
return nil, runconfig.ErrConflictSharedNetwork
|
||||
}
|
||||
|
||||
if containertypes.NetworkMode(idOrName).IsBridge() &&
|
||||
daemon.configStore.DisableBridge {
|
||||
container.Config.NetworkDisabled = true
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if !containertypes.NetworkMode(idOrName).IsUserDefined() {
|
||||
func (daemon *Daemon) updateNetworkConfig(container *container.Container, n libnetwork.Network, endpointConfig *networktypes.EndpointSettings, updateSettings bool) error {
|
||||
if !containertypes.NetworkMode(n.Name()).IsUserDefined() {
|
||||
if hasUserDefinedIPAddress(endpointConfig) && !enableIPOnPredefinedNetwork() {
|
||||
return nil, runconfig.ErrUnsupportedNetworkAndIP
|
||||
return runconfig.ErrUnsupportedNetworkAndIP
|
||||
}
|
||||
if endpointConfig != nil && len(endpointConfig.Aliases) > 0 {
|
||||
return nil, runconfig.ErrUnsupportedNetworkAndAlias
|
||||
return runconfig.ErrUnsupportedNetworkAndAlias
|
||||
}
|
||||
} else {
|
||||
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 {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
if updateSettings {
|
||||
if err := daemon.updateNetworkSettings(container, n); err != nil {
|
||||
return nil, err
|
||||
if err := daemon.updateNetworkSettings(container, n, endpointConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return n, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
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 {
|
||||
endpointConfig = &networktypes.EndpointSettings{}
|
||||
}
|
||||
n, err := daemon.updateNetworkConfig(container, idOrName, endpointConfig, updateSettings)
|
||||
|
||||
n, config, err := daemon.findAndAttachNetwork(container, idOrName, endpointConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -560,6 +648,25 @@ func (daemon *Daemon) connectToNetwork(container *container.Container, idOrName
|
|||
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
|
||||
|
||||
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 {
|
||||
return err
|
||||
|
@ -632,7 +745,7 @@ func (daemon *Daemon) ForceEndpointDelete(name string, networkName string) error
|
|||
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 (
|
||||
ep libnetwork.Endpoint
|
||||
sbox libnetwork.Sandbox
|
||||
|
@ -678,6 +791,13 @@ func disconnectFromNetwork(container *container.Container, n libnetwork.Network,
|
|||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -751,6 +871,11 @@ func (daemon *Daemon) releaseNetwork(container *container.Container) {
|
|||
if nw, err := daemon.FindNetwork(n); err == nil {
|
||||
networks = append(networks, nw)
|
||||
}
|
||||
|
||||
if epSettings.EndpointSettings == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
cleanOperationalData(epSettings)
|
||||
}
|
||||
|
||||
|
@ -765,6 +890,12 @@ func (daemon *Daemon) releaseNetwork(container *container.Container) {
|
|||
}
|
||||
|
||||
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{
|
||||
"container": container.ID,
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ import (
|
|||
networktypes "github.com/docker/docker/api/types/network"
|
||||
"github.com/docker/docker/container"
|
||||
"github.com/docker/docker/daemon/links"
|
||||
"github.com/docker/docker/daemon/network"
|
||||
"github.com/docker/docker/pkg/fileutils"
|
||||
"github.com/docker/docker/pkg/idtools"
|
||||
"github.com/docker/docker/pkg/mount"
|
||||
|
@ -35,7 +36,7 @@ func (daemon *Daemon) setupLinkedContainers(container *container.Container) ([]s
|
|||
children := daemon.children(container)
|
||||
|
||||
bridgeSettings := container.NetworkSettings.Networks[runconfig.DefaultDaemonNetworkMode().NetworkName()]
|
||||
if bridgeSettings == nil {
|
||||
if bridgeSettings == nil || bridgeSettings.EndpointSettings == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
|
@ -45,7 +46,7 @@ func (daemon *Daemon) setupLinkedContainers(container *container.Container) ([]s
|
|||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
|
@ -107,10 +108,17 @@ func (daemon *Daemon) ConnectToNetwork(container *container.Container, idOrName
|
|||
if container.RemovalInProgress || container.Dead {
|
||||
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 {
|
||||
if err := daemon.connectToNetwork(container, idOrName, endpointConfig, true); err != nil {
|
||||
return err
|
||||
|
@ -143,7 +151,7 @@ func (daemon *Daemon) DisconnectFromNetwork(container *container.Container, netw
|
|||
return runconfig.ErrConflictHostNetwork
|
||||
}
|
||||
|
||||
if err := disconnectFromNetwork(container, n, false); err != nil {
|
||||
if err := daemon.disconnectFromNetwork(container, n, false); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -252,7 +252,7 @@ func (daemon *Daemon) verifyNetworkingConfig(nwConfig *networktypes.NetworkingCo
|
|||
}
|
||||
if len(nwConfig.EndpointsConfig) == 1 {
|
||||
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 {
|
||||
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
|
||||
}
|
||||
|
||||
apiNetworks := make(map[string]*networktypes.EndpointSettings)
|
||||
for name, epConf := range container.NetworkSettings.Networks {
|
||||
if epConf.EndpointSettings != nil {
|
||||
apiNetworks[name] = epConf.EndpointSettings
|
||||
}
|
||||
}
|
||||
|
||||
mountPoints := addMountPoints(container)
|
||||
networkSettings := &types.NetworkSettings{
|
||||
NetworkSettingsBase: types.NetworkSettingsBase{
|
||||
|
@ -56,7 +63,7 @@ func (daemon *Daemon) ContainerInspectCurrent(name string, size bool) (*types.Co
|
|||
SecondaryIPv6Addresses: container.NetworkSettings.SecondaryIPv6Addresses,
|
||||
},
|
||||
DefaultNetworkSettings: daemon.getDefaultNetworkSettings(container.NetworkSettings.Networks),
|
||||
Networks: container.NetworkSettings.Networks,
|
||||
Networks: apiNetworks,
|
||||
}
|
||||
|
||||
return &types.ContainerJSON{
|
||||
|
@ -236,10 +243,10 @@ func (daemon *Daemon) getBackwardsCompatibleNetworkSettings(settings *network.Se
|
|||
|
||||
// getDefaultNetworkSettings creates the deprecated structure that holds the information
|
||||
// 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
|
||||
|
||||
if defaultNetwork, ok := networks["bridge"]; ok {
|
||||
if defaultNetwork, ok := networks["bridge"]; ok && defaultNetwork.EndpointSettings != nil {
|
||||
settings.EndpointID = defaultNetwork.EndpointID
|
||||
settings.Gateway = defaultNetwork.Gateway
|
||||
settings.GlobalIPv6Address = defaultNetwork.GlobalIPv6Address
|
||||
|
|
|
@ -400,6 +400,9 @@ func includeContainerInList(container *container.Container, ctx *listContext) it
|
|||
return networkExist
|
||||
}
|
||||
for _, nw := range container.NetworkSettings.Networks {
|
||||
if nw.EndpointSettings == nil {
|
||||
continue
|
||||
}
|
||||
if nw.NetworkID == value {
|
||||
return networkExist
|
||||
}
|
||||
|
@ -460,7 +463,7 @@ func (daemon *Daemon) transformContainer(container *container.Container, ctx *li
|
|||
// copy networks to avoid races
|
||||
networks := make(map[string]*networktypes.EndpointSettings)
|
||||
for name, network := range container.NetworkSettings.Networks {
|
||||
if network == nil {
|
||||
if network == nil || network.EndpointSettings == nil {
|
||||
continue
|
||||
}
|
||||
networks[name] = &networktypes.EndpointSettings{
|
||||
|
|
|
@ -14,6 +14,7 @@ import (
|
|||
"github.com/docker/docker/runconfig"
|
||||
"github.com/docker/libnetwork"
|
||||
networktypes "github.com/docker/libnetwork/types"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// NetworkControllerEnabled checks if the networking stack is enabled.
|
||||
|
@ -186,6 +187,29 @@ func (daemon *Daemon) SetNetworkBootstrapKeys(keys []*networktypes.EncryptionKey
|
|||
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.
|
||||
func (daemon *Daemon) CreateManagedNetwork(create clustertypes.NetworkCreateRequest) error {
|
||||
_, err := daemon.createNetwork(create.NetworkCreateRequest, create.ID, true)
|
||||
|
|
|
@ -14,7 +14,7 @@ type Settings struct {
|
|||
HairpinMode bool
|
||||
LinkLocalIPv6Address string
|
||||
LinkLocalIPv6PrefixLen int
|
||||
Networks map[string]*networktypes.EndpointSettings
|
||||
Networks map[string]*EndpointSettings
|
||||
Service *clustertypes.ServiceConfig
|
||||
Ports nat.PortMap
|
||||
SandboxKey string
|
||||
|
@ -22,3 +22,11 @@ type Settings struct {
|
|||
SecondaryIPv6Addresses []networktypes.Address
|
||||
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 {
|
||||
c.Logf("error removing %v: %v", walDir, err)
|
||||
}
|
||||
|
||||
cleanupExecRoot(c, d.execRoot)
|
||||
}
|
||||
s.daemons = nil
|
||||
s.daemonsLock.Unlock()
|
||||
|
|
|
@ -2,7 +2,29 @@
|
|||
|
||||
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) {
|
||||
syscall.Kill(pid, syscall.SIGQUIT)
|
||||
|
|
|
@ -5,6 +5,8 @@ import (
|
|||
"strconv"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
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 {
|
||||
return fmt.Errorf("daemon reload not supported")
|
||||
}
|
||||
|
||||
func cleanupExecRoot(c *check.C, execRoot string) {
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue