diff --git a/components/engine/daemon/container_operations.go b/components/engine/daemon/container_operations.go index a1a64fec3e..bed184a50c 100644 --- a/components/engine/daemon/container_operations.go +++ b/components/engine/daemon/container_operations.go @@ -346,7 +346,9 @@ func (daemon *Daemon) updateNetwork(container *container.Container) error { } func (daemon *Daemon) findAndAttachNetwork(container *container.Container, idOrName string, epConfig *networktypes.EndpointSettings) (libnetwork.Network, *networktypes.NetworkingConfig, error) { - n, err := daemon.FindNetwork(getNetworkID(idOrName, epConfig)) + id := getNetworkID(idOrName, epConfig) + + n, err := daemon.FindNetwork(id) if err != nil { // We should always be able to find the network for a // managed container. @@ -379,21 +381,26 @@ func (daemon *Daemon) findAndAttachNetwork(container *container.Container, idOrN retryCount int ) + if n == nil && daemon.attachableNetworkLock != nil { + daemon.attachableNetworkLock.Lock(id) + defer daemon.attachableNetworkLock.Unlock(id) + } + for { // In all other cases, attempt to attach to the network to // trigger attachment in the swarm cluster manager. if daemon.clusterProvider != nil { var err error - config, err = daemon.clusterProvider.AttachNetwork(getNetworkID(idOrName, epConfig), container.ID, addresses) + config, err = daemon.clusterProvider.AttachNetwork(id, container.ID, addresses) if err != nil { return nil, nil, err } } - n, err = daemon.FindNetwork(getNetworkID(idOrName, epConfig)) + n, err = daemon.FindNetwork(id) if err != nil { if daemon.clusterProvider != nil { - if err := daemon.clusterProvider.DetachNetwork(getNetworkID(idOrName, epConfig), container.ID); err != nil { + if err := daemon.clusterProvider.DetachNetwork(id, container.ID); err != nil { logrus.Warnf("Could not rollback attachment for container %s to network %s: %v", container.ID, idOrName, err) } } diff --git a/components/engine/daemon/daemon.go b/components/engine/daemon/daemon.go index 0a094e3087..30f6e47f4d 100644 --- a/components/engine/daemon/daemon.go +++ b/components/engine/daemon/daemon.go @@ -43,6 +43,7 @@ import ( "github.com/docker/docker/migrate/v1" "github.com/docker/docker/pkg/containerfs" "github.com/docker/docker/pkg/idtools" + "github.com/docker/docker/pkg/locker" "github.com/docker/docker/pkg/plugingetter" "github.com/docker/docker/pkg/sysinfo" "github.com/docker/docker/pkg/system" @@ -120,7 +121,8 @@ type Daemon struct { hosts map[string]bool // hosts stores the addresses the daemon is listening on startupDone chan struct{} - attachmentStore network.AttachmentStore + attachmentStore network.AttachmentStore + attachableNetworkLock *locker.Locker } // StoreHosts stores the addresses the daemon is listening on @@ -564,6 +566,7 @@ func (daemon *Daemon) DaemonLeavesCluster() { func (daemon *Daemon) setClusterProvider(clusterProvider cluster.Provider) { daemon.clusterProvider = clusterProvider daemon.netController.SetClusterProvider(clusterProvider) + daemon.attachableNetworkLock = locker.New() } // IsSwarmCompatible verifies if the current daemon