// 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 err := config.ValidateName(name); err != nil { return nil, ErrInvalidName(err.Error()) } if id == "" { id = stringid.GenerateRandomID() } defaultIpam := defaultIpamForNetworkType(networkType) // Construct the network object network := &network{ name: name, networkType: networkType, generic: map[string]interface{}{netlabel.GenericData: make(map[string]string)}, ipamType: defaultIpam, id: id, created: time.Now(), 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 { logrus.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 { logrus.Warnf("could not 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) if !c.isDistributedControl() { arrangeIngressFilterRule() } return network, nil }
func (n *network) CreateEndpoint(name string, options ...EndpointOption) (Endpoint, error) { var err error if err = config.ValidateName(name); err != nil { return nil, ErrInvalidName(err.Error()) } 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 }