예제 #1
0
// 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, options ...NetworkOption) (Network, error) {
	if !config.IsValidName(name) {
		return nil, ErrInvalidName(name)
	}

	// Construct the network object
	network := &network{
		name:        name,
		networkType: networkType,
		ipamType:    ipamapi.DefaultIPAM,
		id:          stringid.GenerateRandomID(),
		ctrlr:       c,
		persist:     true,
		drvOnce:     &sync.Once{},
	}

	network.processOptions(options...)

	// Make sure we have a driver available for this network type
	// before we allocate anything.
	if _, err := network.driver(); err != nil {
		return nil, err
	}

	cnfs, err := network.ipamAllocate()
	if err != nil {
		return nil, err
	}
	defer func() {
		if err != nil {
			for _, cn := range cnfs {
				cn()
			}
		}
	}()

	// addNetwork can be called for local scope network lazily when
	// an endpoint is created after a restart and the network was
	// created in previous life. Make sure you wrap around the driver
	// notification of network creation in once call so that the driver
	// invoked only once in case both the network and endpoint creation
	// happens in the same lifetime.
	network.drvOnce.Do(func() {
		err = c.addNetwork(network)
	})
	if err != nil {
		return nil, err
	}

	if err = c.updateToStore(network); err != nil {
		log.Warnf("couldnt create network %s: %v", network.name, err)
		if e := network.Delete(); e != nil {
			log.Warnf("couldnt cleanup network %s on network create failure (%v): %v", network.name, err, e)
		}
		return nil, err
	}

	return network, nil
}
예제 #2
0
// 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, options ...NetworkOption) (Network, error) {
	if !config.IsValidName(name) {
		return nil, ErrInvalidName(name)
	}
	// Check if a network already exists with the specified network name
	c.Lock()
	for _, n := range c.networks {
		if n.name == name {
			c.Unlock()
			return nil, NetworkNameError(name)
		}
	}
	c.Unlock()

	// Construct the network object
	network := &network{
		name:        name,
		networkType: networkType,
		ipamType:    ipamapi.DefaultIPAM,
		id:          stringid.GenerateRandomID(),
		ctrlr:       c,
		endpoints:   endpointTable{},
		persist:     true,
	}

	network.processOptions(options...)

	if _, err := c.loadNetworkDriver(network); err != nil {
		return nil, err
	}

	cnfs, err := network.ipamAllocate()
	if err != nil {
		return nil, err
	}
	defer func() {
		if err != nil {
			for _, cn := range cnfs {
				cn()
			}
		}
	}()

	if err = c.addNetwork(network); err != nil {
		return nil, err
	}

	if err = c.updateToStore(network); err != nil {
		log.Warnf("couldnt create network %s: %v", network.name, err)
		if e := network.Delete(); e != nil {
			log.Warnf("couldnt cleanup network %s on network create failure (%v): %v", network.name, err, e)
		}
		return nil, err
	}

	return network, nil
}
예제 #3
0
파일: network.go 프로젝트: c0b/libnetwork
func (n *network) CreateEndpoint(name string, options ...EndpointOption) (Endpoint, error) {
	var err error
	if !config.IsValidName(name) {
		return nil, ErrInvalidName(name)
	}

	if _, err = n.EndpointByName(name); err == nil {
		return nil, types.ForbiddenErrorf("service endpoint with name %s already exists", name)
	}

	ep := &endpoint{name: name, generic: make(map[string]interface{}), iface: &endpointInterface{}}
	ep.id = stringid.GenerateRandomID()
	ep.network = n
	ep.processOptions(options...)

	if err = ep.assignAddress(); err != nil {
		return nil, err
	}
	defer func() {
		if err != nil {
			ep.releaseAddress()
		}
	}()

	ctrlr := n.getController()

	n.IncEndpointCnt()
	if err = ctrlr.updateToStore(n); err != nil {
		return nil, err
	}
	defer func() {
		if err != nil {
			n.DecEndpointCnt()
			if err = ctrlr.updateToStore(n); err != nil {
				log.Warnf("endpoint count cleanup failed when updating network for %s : %v", name, err)
			}
		}
	}()
	if err = n.addEndpoint(ep); err != nil {
		return nil, err
	}
	defer func() {
		if err != nil {
			if e := ep.Delete(); ep != nil {
				log.Warnf("cleaning up endpoint failed %s : %v", name, e)
			}
		}
	}()

	if !ep.isLocalScoped() {
		if err = ctrlr.updateToStore(ep); err != nil {
			return nil, err
		}
	}

	return ep, nil
}
예제 #4
0
func (n *network) CreateEndpoint(name string, options ...EndpointOption) (Endpoint, error) {
	var err error
	if !config.IsValidName(name) {
		return nil, ErrInvalidName(name)
	}

	if _, err = n.EndpointByName(name); err == nil {
		return nil, types.ForbiddenErrorf("service endpoint with name %s already exists", name)
	}

	ep := &endpoint{name: name,
		iFaces:  []*endpointInterface{},
		generic: make(map[string]interface{})}
	ep.id = types.UUID(stringid.GenerateRandomID())
	ep.network = n
	ep.processOptions(options...)

	n.Lock()
	ctrlr := n.ctrlr
	n.Unlock()

	n.IncEndpointCnt()
	if err = ctrlr.updateNetworkToStore(n); err != nil {
		return nil, err
	}
	defer func() {
		if err != nil {
			n.DecEndpointCnt()
			if err = ctrlr.updateNetworkToStore(n); err != nil {
				log.Warnf("endpoint count cleanup failed when updating network for %s : %v", name, err)
			}
		}
	}()
	if err = n.addEndpoint(ep); err != nil {
		return nil, err
	}
	defer func() {
		if err != nil {
			if e := ep.Delete(); ep != nil {
				log.Warnf("cleaning up endpoint failed %s : %v", name, e)
			}
		}
	}()

	if err = ctrlr.updateEndpointToStore(ep); err != nil {
		return nil, err
	}

	return ep, nil
}
예제 #5
0
func (c *controller) RegisterDriver(networkType string, driver driverapi.Driver, capability driverapi.Capability) error {
	if !config.IsValidName(networkType) {
		return ErrInvalidName(networkType)
	}

	c.Lock()
	if _, ok := c.drivers[networkType]; ok {
		c.Unlock()
		return driverapi.ErrActiveRegistration(networkType)
	}
	c.drivers[networkType] = &driverData{driver, capability}
	c.Unlock()

	return nil
}
예제 #6
0
func (c *controller) RegisterDriver(networkType string, driver driverapi.Driver, capability driverapi.Capability) error {
	c.Lock()
	if !config.IsValidName(networkType) {
		c.Unlock()
		return ErrInvalidName(networkType)
	}
	if _, ok := c.drivers[networkType]; ok {
		c.Unlock()
		return driverapi.ErrActiveRegistration(networkType)
	}
	c.drivers[networkType] = &driverData{driver, capability}

	if c.cfg == nil {
		c.Unlock()
		return nil
	}

	opt := make(map[string]interface{})
	for _, label := range c.cfg.Daemon.Labels {
		if strings.HasPrefix(label, netlabel.DriverPrefix+"."+networkType) {
			opt[netlabel.Key(label)] = netlabel.Value(label)
		}
	}

	if capability.DataScope == datastore.GlobalScope && c.validateGlobalStoreConfig() {
		opt[netlabel.KVProvider] = c.cfg.GlobalStore.Client.Provider
		opt[netlabel.KVProviderURL] = c.cfg.GlobalStore.Client.Address
	}

	if capability.DataScope == datastore.LocalScope {
		localStoreConfig := c.getLocalStoreConfig(c.cfg)
		opt[netlabel.KVProvider] = localStoreConfig.Client.Provider
		opt[netlabel.KVProviderURL] = localStoreConfig.Client.Address
		opt[netlabel.KVProviderConfig] = localStoreConfig.Client.Config
	}

	c.Unlock()

	if len(opt) != 0 {
		if err := driver.Config(opt); err != nil {
			return err
		}
	}

	return nil
}
예제 #7
0
func (c *controller) RegisterDriver(networkType string, driver driverapi.Driver, capability driverapi.Capability) error {
	if !config.IsValidName(networkType) {
		return ErrInvalidName(networkType)
	}

	c.Lock()
	if _, ok := c.drivers[networkType]; ok {
		c.Unlock()
		return driverapi.ErrActiveRegistration(networkType)
	}
	dData := &driverData{driver, capability}
	c.drivers[networkType] = dData
	hd := c.discovery
	c.Unlock()

	if hd != nil {
		c.pushNodeDiscovery(dData, hd.Fetch(), true)
	}

	return nil
}
예제 #8
0
// 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, options ...NetworkOption) (Network, error) {
	if !config.IsValidName(name) {
		return nil, ErrInvalidName(name)
	}
	// Check if a network already exists with the specified network name
	c.Lock()
	for _, n := range c.networks {
		if n.name == name {
			c.Unlock()
			return n, nil
			//			return nil, NetworkNameError(name)
		}
	}
	c.Unlock()

	// Construct the network object
	network := &network{
		name:        name,
		networkType: networkType,
		id:          stringid.GenerateRandomID(),
		ctrlr:       c,
		endpoints:   endpointTable{},
	}

	network.processOptions(options...)

	if err := c.addNetwork(network); err != nil {
		return nil, err
	}

	if err := c.updateNetworkToStore(network); err != nil {
		log.Warnf("couldnt create network %s: %v", network.name, err)
		if e := network.Delete(); e != nil {
			log.Warnf("couldnt cleanup network %s: %v", network.name, err)
		}
		return nil, err
	}

	return network, nil
}
예제 #9
0
func (c *controller) RegisterIpamDriver(name string, driver ipamapi.Ipam) error {
	if !config.IsValidName(name) {
		return ErrInvalidName(name)
	}

	c.Lock()
	_, ok := c.ipamDrivers[name]
	c.Unlock()
	if ok {
		return driverapi.ErrActiveRegistration(name)
	}
	locAS, glbAS, err := driver.GetDefaultAddressSpaces()
	if err != nil {
		return fmt.Errorf("ipam driver %s failed to return default address spaces: %v", name, err)
	}
	c.Lock()
	c.ipamDrivers[name] = &ipamData{driver: driver, defaultLocalAddressSpace: locAS, defaultGlobalAddressSpace: glbAS}
	c.Unlock()

	log.Debugf("Registering ipam provider: %s", name)

	return nil
}
예제 #10
0
func (c *controller) registerIpamDriver(name string, driver ipamapi.Ipam, caps *ipamapi.Capability) error {
	if !config.IsValidName(name) {
		return ErrInvalidName(name)
	}

	c.Lock()
	_, ok := c.ipamDrivers[name]
	c.Unlock()
	if ok {
		return types.ForbiddenErrorf("ipam driver %q already registered", name)
	}
	locAS, glbAS, err := driver.GetDefaultAddressSpaces()
	if err != nil {
		return types.InternalErrorf("ipam driver %q failed to return default address spaces: %v", name, err)
	}
	c.Lock()
	c.ipamDrivers[name] = &ipamData{driver: driver, defaultLocalAddressSpace: locAS, defaultGlobalAddressSpace: glbAS, capability: caps}
	c.Unlock()

	log.Debugf("Registering ipam driver: %q", name)

	return nil
}
예제 #11
0
// 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 !config.IsValidName(name) {
		return nil, ErrInvalidName(name)
	}

	if id == "" {
		id = stringid.GenerateRandomID()
	}

	// Construct the network object
	network := &network{
		name:        name,
		networkType: networkType,
		generic:     map[string]interface{}{netlabel.GenericData: make(map[string]string)},
		ipamType:    ipamapi.DefaultIPAM,
		id:          id,
		ctrlr:       c,
		persist:     true,
		drvOnce:     &sync.Once{},
	}

	network.processOptions(options...)

	_, cap, err := network.resolveDriver(networkType, true)
	if err != nil {
		return nil, err
	}

	if cap.DataScope == datastore.GlobalScope && !c.isDistributedControl() && !network.dynamic {
		if c.isManager() {
			// For non-distributed controlled environment, globalscoped non-dynamic networks are redirected to Manager
			return nil, ManagerRedirectError(name)
		}

		return nil, types.ForbiddenErrorf("Cannot create a multi-host network from a worker node. Please create the network from a manager node.")
	}

	// Make sure we have a driver available for this network type
	// before we allocate anything.
	if _, err := network.driver(true); err != nil {
		return nil, err
	}

	err = network.ipamAllocate()
	if err != nil {
		return nil, err
	}
	defer func() {
		if err != nil {
			network.ipamRelease()
		}
	}()

	err = c.addNetwork(network)
	if err != nil {
		return nil, err
	}
	defer func() {
		if err != nil {
			if e := network.deleteNetwork(); e != nil {
				log.Warnf("couldn't roll back driver network on network %s creation failure: %v", network.name, err)
			}
		}
	}()

	// First store the endpoint count, then the network. To avoid to
	// end up with a datastore containing a network and not an epCnt,
	// in case of an ungraceful shutdown during this function call.
	epCnt := &endpointCnt{n: network}
	if err = c.updateToStore(epCnt); err != nil {
		return nil, err
	}
	defer func() {
		if err != nil {
			if e := c.deleteFromStore(epCnt); e != nil {
				log.Warnf("couldnt rollback from store, epCnt %v on failure (%v): %v", epCnt, err, e)
			}
		}
	}()

	network.epCnt = epCnt
	if err = c.updateToStore(network); err != nil {
		return nil, err
	}

	joinCluster(network)

	return network, nil
}
예제 #12
0
func (n *network) CreateEndpoint(name string, options ...EndpointOption) (Endpoint, error) {
	var err error
	if !config.IsValidName(name) {
		return nil, ErrInvalidName(name)
	}

	if _, err = n.EndpointByName(name); err == nil {
		return nil, types.ForbiddenErrorf("service endpoint with name %s already exists", name)
	}

	ep := &endpoint{name: name, generic: make(map[string]interface{}), iface: &endpointInterface{}}
	ep.id = stringid.GenerateRandomID()

	// Initialize ep.network with a possibly stale copy of n. We need this to get network from
	// store. But once we get it from store we will have the most uptodate copy possibly.
	ep.network = n
	ep.locator = n.getController().clusterHostID()
	ep.network, err = ep.getNetworkFromStore()
	if err != nil {
		return nil, fmt.Errorf("failed to get network during CreateEndpoint: %v", err)
	}
	n = ep.network

	ep.processOptions(options...)

	for _, llIPNet := range ep.Iface().LinkLocalAddresses() {
		if !llIPNet.IP.IsLinkLocalUnicast() {
			return nil, types.BadRequestErrorf("invalid link local IP address: %v", llIPNet.IP)
		}
	}

	if opt, ok := ep.generic[netlabel.MacAddress]; ok {
		if mac, ok := opt.(net.HardwareAddr); ok {
			ep.iface.mac = mac
		}
	}

	ipam, cap, err := n.getController().getIPAMDriver(n.ipamType)
	if err != nil {
		return nil, err
	}

	if cap.RequiresMACAddress {
		if ep.iface.mac == nil {
			ep.iface.mac = netutils.GenerateRandomMAC()
		}
		if ep.ipamOptions == nil {
			ep.ipamOptions = make(map[string]string)
		}
		ep.ipamOptions[netlabel.MacAddress] = ep.iface.mac.String()
	}

	if err = ep.assignAddress(ipam, true, n.enableIPv6 && !n.postIPv6); err != nil {
		return nil, err
	}
	defer func() {
		if err != nil {
			ep.releaseAddress()
		}
	}()

	if err = n.addEndpoint(ep); err != nil {
		return nil, err
	}
	defer func() {
		if err != nil {
			if e := ep.deleteEndpoint(false); e != nil {
				log.Warnf("cleaning up endpoint failed %s : %v", name, e)
			}
		}
	}()

	if err = ep.assignAddress(ipam, false, n.enableIPv6 && n.postIPv6); err != nil {
		return nil, err
	}

	if err = n.getController().updateToStore(ep); err != nil {
		return nil, err
	}
	defer func() {
		if err != nil {
			if e := n.getController().deleteFromStore(ep); e != nil {
				log.Warnf("error rolling back endpoint %s from store: %v", name, e)
			}
		}
	}()

	// Watch for service records
	n.getController().watchSvcRecord(ep)
	defer func() {
		if err != nil {
			n.getController().unWatchSvcRecord(ep)
		}
	}()

	// Increment endpoint count to indicate completion of endpoint addition
	if err = n.getEpCnt().IncEndpointCnt(); err != nil {
		return nil, err
	}

	return ep, nil
}
예제 #13
0
func (n *network) CreateEndpoint(name string, options ...EndpointOption) (Endpoint, error) {
	var err error
	if !config.IsValidName(name) {
		return nil, ErrInvalidName(name)
	}

	if _, err = n.EndpointByName(name); err == nil {
		return nil, types.ForbiddenErrorf("service endpoint with name %s already exists", name)
	}

	ep := &endpoint{name: name, generic: make(map[string]interface{}), iface: &endpointInterface{}}
	ep.id = stringid.GenerateRandomID()

	// Initialize ep.network with a possibly stale copy of n. We need this to get network from
	// store. But once we get it from store we will have the most uptodate copy possible.
	ep.network = n
	ep.network, err = ep.getNetworkFromStore()
	if err != nil {
		return nil, fmt.Errorf("failed to get network during CreateEndpoint: %v", err)
	}
	n = ep.network

	ep.processOptions(options...)

	if opt, ok := ep.generic[netlabel.MacAddress]; ok {
		if mac, ok := opt.(net.HardwareAddr); ok {
			ep.iface.mac = mac
		}
	}

	if err = ep.assignAddress(true, !n.postIPv6); err != nil {
		return nil, err
	}
	defer func() {
		if err != nil {
			ep.releaseAddress()
		}
	}()

	if err = n.addEndpoint(ep); err != nil {
		return nil, err
	}
	defer func() {
		if err != nil {
			if e := ep.deleteEndpoint(); e != nil {
				log.Warnf("cleaning up endpoint failed %s : %v", name, e)
			}
		}
	}()

	if err = ep.assignAddress(false, n.postIPv6); err != nil {
		return nil, err
	}

	if err = n.getController().updateToStore(ep); err != nil {
		return nil, err
	}
	defer func() {
		if err != nil {
			if e := n.getController().deleteFromStore(ep); e != nil {
				log.Warnf("error rolling back endpoint %s from store: %v", name, e)
			}
		}
	}()

	// Watch for service records
	n.getController().watchSvcRecord(ep)
	defer func() {
		if err != nil {
			n.getController().unWatchSvcRecord(ep)
		}
	}()

	// Increment endpoint count to indicate completion of endpoint addition
	if err = n.getEpCnt().IncEndpointCnt(); err != nil {
		return nil, err
	}

	return ep, nil
}
예제 #14
0
// 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, options ...NetworkOption) (Network, error) {
	if !config.IsValidName(name) {
		return nil, ErrInvalidName(name)
	}

	// Construct the network object
	network := &network{
		name:        name,
		networkType: networkType,
		generic:     map[string]interface{}{netlabel.GenericData: make(map[string]string)},
		ipamType:    ipamapi.DefaultIPAM,
		id:          stringid.GenerateRandomID(),
		ctrlr:       c,
		persist:     true,
		drvOnce:     &sync.Once{},
	}

	network.processOptions(options...)

	// Make sure we have a driver available for this network type
	// before we allocate anything.
	if _, err := network.driver(); err != nil {
		return nil, err
	}

	err := network.ipamAllocate()
	if err != nil {
		return nil, err
	}
	defer func() {
		if err != nil {
			network.ipamRelease()
		}
	}()

	if err = c.addNetwork(network); err != nil {
		return nil, err
	}
	defer func() {
		if err != nil {
			if e := network.deleteNetwork(); e != nil {
				log.Warnf("couldn't roll back driver network on network %s creation failure: %v", network.name, err)
			}
		}
	}()

	if err = c.updateToStore(network); err != nil {
		return nil, err
	}
	defer func() {
		if err != nil {
			if e := c.deleteFromStore(network); e != nil {
				log.Warnf("couldnt rollback from store, network %s on failure (%v): %v", network.name, err, e)
			}
		}
	}()

	network.epCnt = &endpointCnt{n: network}
	if err = c.updateToStore(network.epCnt); err != nil {
		return nil, err
	}

	return network, nil
}
예제 #15
0
// 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, options ...NetworkOption) (Network, error) {

	//验证网络的名称是否符合规范。
	if !config.IsValidName(name) {
		return nil, ErrInvalidName(name)
	}

	// Construct the network object
	//创建网络的对象。在libnetwork/network.go中。
	network := &network{
		name:        name,
		networkType: networkType,
		generic:     map[string]interface{}{netlabel.GenericData: make(map[string]string)},
		ipamType:    ipamapi.DefaultIPAM,
		id:          stringid.GenerateRandomID(),
		ctrlr:       c,
		persist:     true,
		drvOnce:     &sync.Once{},
	}

	//分解配置。
	network.processOptions(options...)

	// Make sure we have a driver available for this network type
	// before we allocate anything.
	//确定该driver确实存在。就是检查network中的controller的drivers是否含有该networktype。
	if _, err := network.driver(true); err != nil {
		return nil, err
	}

	//预留本宿主机可以使用的ip地址池。
	//周飒仔细研究。
	err := network.ipamAllocate()
	if err != nil {
		return nil, err
	}
	defer func() {
		if err != nil {
			network.ipamRelease()
		}
	}()

	//增加给网络模式。
	if err = c.addNetwork(network); err != nil {
		return nil, err
	}
	defer func() {
		if err != nil {
			if e := network.deleteNetwork(); e != nil {
				log.Warnf("couldn't roll back driver network on network %s creation failure: %v", network.name, err)
			}
		}
	}()

	// First store the endpoint count, then the network. To avoid to
	// end up with a datastore containing a network and not an epCnt,
	// in case of an ungraceful shutdown during this function call.
	epCnt := &endpointCnt{n: network}
	if err = c.updateToStore(epCnt); err != nil {
		return nil, err
	}
	defer func() {
		if err != nil {
			if e := c.deleteFromStore(epCnt); e != nil {
				log.Warnf("couldnt rollback from store, epCnt %v on failure (%v): %v", epCnt, err, e)
			}
		}
	}()

	network.epCnt = epCnt
	if err = c.updateToStore(network); err != nil {
		return nil, err
	}

	return network, nil
}
예제 #16
0
// 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 !config.IsValidName(name) {
		return nil, ErrInvalidName(name)
	}

	if id == "" {
		id = stringid.GenerateRandomID()
	}

	// Construct the network object
	network := &network{
		name:        name,
		networkType: networkType,
		generic:     map[string]interface{}{netlabel.GenericData: make(map[string]string)},
		ipamType:    ipamapi.DefaultIPAM,
		id:          id,
		ctrlr:       c,
		persist:     true,
		drvOnce:     &sync.Once{},
	}

	network.processOptions(options...)

	// Make sure we have a driver available for this network type
	// before we allocate anything.
	if _, err := network.driver(true); err != nil {
		return nil, err
	}

	err := network.ipamAllocate()
	if err != nil {
		return nil, err
	}
	defer func() {
		if err != nil {
			network.ipamRelease()
		}
	}()

	err = c.addNetwork(network)
	if err != nil {
		return nil, err
	}
	defer func() {
		if err != nil {
			if e := network.deleteNetwork(); e != nil {
				log.Warnf("couldn't roll back driver network on network %s creation failure: %v", network.name, err)
			}
		}
	}()

	// First store the endpoint count, then the network. To avoid to
	// end up with a datastore containing a network and not an epCnt,
	// in case of an ungraceful shutdown during this function call.
	epCnt := &endpointCnt{n: network}
	if err = c.updateToStore(epCnt); err != nil {
		return nil, err
	}
	defer func() {
		if err != nil {
			if e := c.deleteFromStore(epCnt); e != nil {
				log.Warnf("couldnt rollback from store, epCnt %v on failure (%v): %v", epCnt, err, e)
			}
		}
	}()

	network.epCnt = epCnt
	if err = c.updateToStore(network); err != nil {
		return nil, err
	}

	if err = network.joinCluster(); err != nil {
		log.Errorf("Failed to join network %s into agent cluster: %v", name, err)
	}

	network.addDriverWatches()

	return network, nil
}