From ff59f1baaba50f32674b6b2d07730cd44bde8267 Mon Sep 17 00:00:00 2001 From: Jana Radhakrishnan Date: Mon, 12 Sep 2016 15:19:22 -0700 Subject: [PATCH] Serialize dynamic network creation When dynamic networks are created and there is a race in creation of the same network from two different tasks then one of them will fail while the other will succeed. For service tasks this is not a big problem because they will be rescheduled again. But for attachment tasks this can be a problem since they won't get recreated and making the whole connection fail. Fixed it by serializing network creation for the network with the same id and trying to see if the id is present after coming out of wait. Signed-off-by: Jana Radhakrishnan --- libnetwork/controller.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/libnetwork/controller.go b/libnetwork/controller.go index b2499dc7f5..c63535d1b8 100644 --- a/libnetwork/controller.go +++ b/libnetwork/controller.go @@ -52,6 +52,7 @@ import ( log "github.com/Sirupsen/logrus" "github.com/docker/docker/pkg/discovery" + "github.com/docker/docker/pkg/locker" "github.com/docker/docker/pkg/plugins" "github.com/docker/docker/pkg/stringid" "github.com/docker/libnetwork/cluster" @@ -149,6 +150,7 @@ type controller struct { ingressSandbox *sandbox sboxOnce sync.Once agent *agent + networkLocker *locker.Locker agentInitDone chan struct{} keys []*types.EncryptionKey clusterConfigAvailable bool @@ -169,6 +171,7 @@ func New(cfgOptions ...config.Option) (NetworkController, error) { svcRecords: make(map[string]svcInfo), serviceBindings: make(map[serviceKey]*service), agentInitDone: make(chan struct{}), + networkLocker: locker.New(), } if err := c.initStores(); err != nil { @@ -614,6 +617,15 @@ func (c *controller) RegisterDriver(networkType string, driver driverapi.Driver, // NewNetwork creates a new network of the specified network type. The options // are network specific and modeled in a generic way. func (c *controller) NewNetwork(networkType, name string, id string, options ...NetworkOption) (Network, error) { + if id != "" { + c.networkLocker.Lock(id) + defer c.networkLocker.Unlock(id) + + if _, err := c.NetworkByID(id); err == nil { + return nil, NetworkNameError(id) + } + } + if !config.IsValidName(name) { return nil, ErrInvalidName(name) }