|
@@ -1,408 +1,348 @@
|
|
|
package libnetwork
|
|
|
|
|
|
import (
|
|
|
- "encoding/json"
|
|
|
"fmt"
|
|
|
- "time"
|
|
|
|
|
|
log "github.com/Sirupsen/logrus"
|
|
|
- "github.com/docker/libkv/store"
|
|
|
- "github.com/docker/libnetwork/config"
|
|
|
"github.com/docker/libnetwork/datastore"
|
|
|
)
|
|
|
|
|
|
-var (
|
|
|
- defaultBoltTimeout = 3 * time.Second
|
|
|
- defaultLocalStoreConfig = config.DatastoreCfg{
|
|
|
- Embedded: true,
|
|
|
- Client: config.DatastoreClientCfg{
|
|
|
- Provider: "boltdb",
|
|
|
- Address: defaultPrefix + "/boltdb.db",
|
|
|
- Config: &store.Config{
|
|
|
- Bucket: "libnetwork",
|
|
|
- ConnectionTimeout: defaultBoltTimeout,
|
|
|
- },
|
|
|
- },
|
|
|
- }
|
|
|
-)
|
|
|
-
|
|
|
-func (c *controller) validateGlobalStoreConfig() bool {
|
|
|
- return c.cfg != nil && c.cfg.GlobalStore.Client.Provider != "" && c.cfg.GlobalStore.Client.Address != ""
|
|
|
-}
|
|
|
-
|
|
|
-func (c *controller) initGlobalStore() error {
|
|
|
+func (c *controller) initStores() error {
|
|
|
c.Lock()
|
|
|
- cfg := c.cfg
|
|
|
- c.Unlock()
|
|
|
- if !c.validateGlobalStoreConfig() {
|
|
|
- return fmt.Errorf("globalstore initialization requires a valid configuration")
|
|
|
+ if c.cfg == nil {
|
|
|
+ c.Unlock()
|
|
|
+ return nil
|
|
|
}
|
|
|
+ scopeConfigs := c.cfg.Scopes
|
|
|
+ c.Unlock()
|
|
|
|
|
|
- store, err := datastore.NewDataStore(&cfg.GlobalStore)
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
+ for scope, scfg := range scopeConfigs {
|
|
|
+ store, err := datastore.NewDataStore(scope, scfg)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ c.Lock()
|
|
|
+ c.stores = append(c.stores, store)
|
|
|
+ c.Unlock()
|
|
|
}
|
|
|
- c.Lock()
|
|
|
- c.globalStore = store
|
|
|
- c.Unlock()
|
|
|
+
|
|
|
+ c.startWatch()
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
-func (c *controller) initLocalStore() error {
|
|
|
- c.Lock()
|
|
|
- cfg := c.cfg
|
|
|
- c.Unlock()
|
|
|
- localStore, err := datastore.NewDataStore(c.getLocalStoreConfig(cfg))
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
+func (c *controller) closeStores() {
|
|
|
+ for _, store := range c.getStores() {
|
|
|
+ store.Close()
|
|
|
}
|
|
|
- c.Lock()
|
|
|
- c.localStore = localStore
|
|
|
- c.Unlock()
|
|
|
- return nil
|
|
|
}
|
|
|
|
|
|
-func (c *controller) restoreFromGlobalStore() error {
|
|
|
+func (c *controller) getStore(scope string) datastore.DataStore {
|
|
|
c.Lock()
|
|
|
- s := c.globalStore
|
|
|
- c.Unlock()
|
|
|
- if s == nil {
|
|
|
- return nil
|
|
|
+ defer c.Unlock()
|
|
|
+
|
|
|
+ for _, store := range c.stores {
|
|
|
+ if store.Scope() == scope {
|
|
|
+ return store
|
|
|
+ }
|
|
|
}
|
|
|
- c.restore("global")
|
|
|
- return c.watchNetworks()
|
|
|
+
|
|
|
+ return nil
|
|
|
}
|
|
|
|
|
|
-func (c *controller) restoreFromLocalStore() error {
|
|
|
+func (c *controller) getStores() []datastore.DataStore {
|
|
|
c.Lock()
|
|
|
- s := c.localStore
|
|
|
- c.Unlock()
|
|
|
- if s != nil {
|
|
|
- c.restore("local")
|
|
|
- }
|
|
|
- return nil
|
|
|
+ defer c.Unlock()
|
|
|
+
|
|
|
+ return c.stores
|
|
|
}
|
|
|
|
|
|
-func (c *controller) restore(store string) {
|
|
|
- nws, err := c.getNetworksFromStore(store == "global")
|
|
|
- if err == nil {
|
|
|
- c.processNetworkUpdate(nws, nil)
|
|
|
- } else if err != datastore.ErrKeyNotFound {
|
|
|
- log.Warnf("failed to read networks from %s store during init : %v", store, err)
|
|
|
+func (c *controller) getNetworkFromStore(nid string) (*network, error) {
|
|
|
+ for _, store := range c.getStores() {
|
|
|
+ n := &network{id: nid, ctrlr: c}
|
|
|
+ err := store.GetObject(datastore.Key(n.Key()...), n)
|
|
|
+ if err != nil && err != datastore.ErrKeyNotFound {
|
|
|
+ return nil, fmt.Errorf("could not find network %s: %v", nid, err)
|
|
|
+ }
|
|
|
+
|
|
|
+ // Continue searching in the next store if the key is not found in this store
|
|
|
+ if err == datastore.ErrKeyNotFound {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ return n, nil
|
|
|
}
|
|
|
+
|
|
|
+ return nil, fmt.Errorf("network %s not found", nid)
|
|
|
}
|
|
|
|
|
|
-func (c *controller) getNetworksFromStore(global bool) ([]*store.KVPair, error) {
|
|
|
- var cs datastore.DataStore
|
|
|
- c.Lock()
|
|
|
- if global {
|
|
|
- cs = c.globalStore
|
|
|
- } else {
|
|
|
- cs = c.localStore
|
|
|
+func (c *controller) getNetworksFromStore() ([]*network, error) {
|
|
|
+ var nl []*network
|
|
|
+
|
|
|
+ for _, store := range c.getStores() {
|
|
|
+ kvol, err := store.List(datastore.Key(datastore.NetworkKeyPrefix),
|
|
|
+ &network{ctrlr: c})
|
|
|
+ if err != nil && err != datastore.ErrKeyNotFound {
|
|
|
+ return nil, fmt.Errorf("failed to get networks for scope %s: %v",
|
|
|
+ store.Scope(), err)
|
|
|
+ }
|
|
|
+
|
|
|
+ // Continue searching in the next store if no keys found in this store
|
|
|
+ if err == datastore.ErrKeyNotFound {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ for _, kvo := range kvol {
|
|
|
+ n := kvo.(*network)
|
|
|
+ n.ctrlr = c
|
|
|
+ nl = append(nl, n)
|
|
|
+ }
|
|
|
}
|
|
|
- c.Unlock()
|
|
|
- return cs.KVStore().List(datastore.Key(datastore.NetworkKeyPrefix))
|
|
|
+
|
|
|
+ return nl, nil
|
|
|
}
|
|
|
|
|
|
-func (c *controller) newNetworkFromStore(n *network) error {
|
|
|
- n.Lock()
|
|
|
- n.ctrlr = c
|
|
|
- n.endpoints = endpointTable{}
|
|
|
- n.Unlock()
|
|
|
+func (n *network) getEndpointFromStore(eid string) (*endpoint, error) {
|
|
|
+ for _, store := range n.ctrlr.getStores() {
|
|
|
+ ep := &endpoint{id: eid, network: n}
|
|
|
+ err := store.GetObject(datastore.Key(ep.Key()...), ep)
|
|
|
+ if err != nil && err != datastore.ErrKeyNotFound {
|
|
|
+ return nil, fmt.Errorf("could not find endpoint %s: %v", eid, err)
|
|
|
+ }
|
|
|
+
|
|
|
+ // Continue searching in the next store if the key is not found in this store
|
|
|
+ if err == datastore.ErrKeyNotFound {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ return ep, nil
|
|
|
+ }
|
|
|
|
|
|
- return c.addNetwork(n)
|
|
|
+ return nil, fmt.Errorf("endpoint %s not found", eid)
|
|
|
}
|
|
|
|
|
|
-func (c *controller) newEndpointFromStore(key string, ep *endpoint) error {
|
|
|
- ep.Lock()
|
|
|
- n := ep.network
|
|
|
- id := ep.id
|
|
|
- ep.Unlock()
|
|
|
+func (n *network) getEndpointsFromStore() ([]*endpoint, error) {
|
|
|
+ var epl []*endpoint
|
|
|
|
|
|
- _, err := n.EndpointByID(id)
|
|
|
- if err != nil {
|
|
|
- if _, ok := err.(ErrNoSuchEndpoint); ok {
|
|
|
- return n.addEndpoint(ep)
|
|
|
+ tmp := endpoint{network: n}
|
|
|
+ for _, store := range n.getController().getStores() {
|
|
|
+ kvol, err := store.List(datastore.Key(tmp.KeyPrefix()...), &endpoint{network: n})
|
|
|
+ if err != nil && err != datastore.ErrKeyNotFound {
|
|
|
+ return nil,
|
|
|
+ fmt.Errorf("failed to get endpoints for network %s scope %s: %v",
|
|
|
+ n.Name(), store.Scope(), err)
|
|
|
+ }
|
|
|
+
|
|
|
+ // Continue searching in the next store if no keys found in this store
|
|
|
+ if err == datastore.ErrKeyNotFound {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ for _, kvo := range kvol {
|
|
|
+ ep := kvo.(*endpoint)
|
|
|
+ ep.network = n
|
|
|
+ epl = append(epl, ep)
|
|
|
}
|
|
|
}
|
|
|
- return err
|
|
|
+
|
|
|
+ return epl, nil
|
|
|
}
|
|
|
|
|
|
-func (c *controller) updateToStore(kvObject datastore.KV) error {
|
|
|
- if kvObject.Skip() {
|
|
|
- return nil
|
|
|
- }
|
|
|
- cs := c.getDataStore(kvObject.DataScope())
|
|
|
+func (c *controller) updateToStore(kvObject datastore.KVObject) error {
|
|
|
+ cs := c.getStore(kvObject.DataScope())
|
|
|
if cs == nil {
|
|
|
- log.Debugf("datastore not initialized. kv object %s is not added to the store", datastore.Key(kvObject.Key()...))
|
|
|
+ log.Warnf("datastore for scope %s not initialized. kv object %s is not added to the store", kvObject.DataScope(), datastore.Key(kvObject.Key()...))
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
- return cs.PutObjectAtomic(kvObject)
|
|
|
+ if err := cs.PutObjectAtomic(kvObject); err != nil {
|
|
|
+ return fmt.Errorf("failed to update store for object type %T: %v", kvObject, err)
|
|
|
+ }
|
|
|
+
|
|
|
+ return nil
|
|
|
}
|
|
|
|
|
|
-func (c *controller) deleteFromStore(kvObject datastore.KV) error {
|
|
|
- if kvObject.Skip() {
|
|
|
- return nil
|
|
|
- }
|
|
|
- cs := c.getDataStore(kvObject.DataScope())
|
|
|
+func (c *controller) deleteFromStore(kvObject datastore.KVObject) error {
|
|
|
+ cs := c.getStore(kvObject.DataScope())
|
|
|
if cs == nil {
|
|
|
- log.Debugf("datastore not initialized. kv object %s is not deleted from datastore", datastore.Key(kvObject.Key()...))
|
|
|
+ log.Debugf("datastore for scope %s not initialized. kv object %s is not deleted from datastore", kvObject.DataScope(), datastore.Key(kvObject.Key()...))
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
+retry:
|
|
|
if err := cs.DeleteObjectAtomic(kvObject); err != nil {
|
|
|
+ if err == datastore.ErrKeyModified {
|
|
|
+ if err := cs.GetObject(datastore.Key(kvObject.Key()...), kvObject); err != nil {
|
|
|
+ return fmt.Errorf("could not update the kvobject to latest when trying to delete: %v", err)
|
|
|
+ }
|
|
|
+ goto retry
|
|
|
+ }
|
|
|
return err
|
|
|
}
|
|
|
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
-func (c *controller) watchNetworks() error {
|
|
|
- if !c.validateGlobalStoreConfig() {
|
|
|
- return nil
|
|
|
- }
|
|
|
+type netWatch struct {
|
|
|
+ localEps map[string]*endpoint
|
|
|
+ remoteEps map[string]*endpoint
|
|
|
+ stopCh chan struct{}
|
|
|
+}
|
|
|
|
|
|
+func (c *controller) getLocalEps(nw *netWatch) []*endpoint {
|
|
|
c.Lock()
|
|
|
- cs := c.globalStore
|
|
|
- c.Unlock()
|
|
|
+ defer c.Unlock()
|
|
|
|
|
|
- networkKey := datastore.Key(datastore.NetworkKeyPrefix)
|
|
|
- if err := ensureKeys(networkKey, cs); err != nil {
|
|
|
- return fmt.Errorf("failed to ensure if the network keys are valid and present in store: %v", err)
|
|
|
+ var epl []*endpoint
|
|
|
+ for _, ep := range nw.localEps {
|
|
|
+ epl = append(epl, ep)
|
|
|
}
|
|
|
- nwPairs, err := cs.KVStore().WatchTree(networkKey, nil)
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
- go func() {
|
|
|
- for {
|
|
|
- select {
|
|
|
- case nws := <-nwPairs:
|
|
|
- c.Lock()
|
|
|
- tmpview := networkTable{}
|
|
|
- lview := c.networks
|
|
|
- c.Unlock()
|
|
|
- for k, v := range lview {
|
|
|
- if v.isGlobalScoped() {
|
|
|
- tmpview[k] = v
|
|
|
- }
|
|
|
- }
|
|
|
- c.processNetworkUpdate(nws, &tmpview)
|
|
|
-
|
|
|
- // Delete processing
|
|
|
- for k := range tmpview {
|
|
|
- c.Lock()
|
|
|
- existing, ok := c.networks[k]
|
|
|
- c.Unlock()
|
|
|
- if !ok {
|
|
|
- continue
|
|
|
- }
|
|
|
- tmp := network{}
|
|
|
- if err := c.globalStore.GetObject(datastore.Key(existing.Key()...), &tmp); err != datastore.ErrKeyNotFound {
|
|
|
- continue
|
|
|
- }
|
|
|
- if err := existing.deleteNetwork(); err != nil {
|
|
|
- log.Debugf("Delete failed %s: %s", existing.name, err)
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }()
|
|
|
- return nil
|
|
|
+
|
|
|
+ return epl
|
|
|
}
|
|
|
|
|
|
-func (n *network) watchEndpoints() error {
|
|
|
- if n.Skip() || !n.ctrlr.validateGlobalStoreConfig() {
|
|
|
- return nil
|
|
|
- }
|
|
|
+func (c *controller) watchSvcRecord(ep *endpoint) {
|
|
|
+ c.watchCh <- ep
|
|
|
+}
|
|
|
|
|
|
- n.Lock()
|
|
|
- cs := n.ctrlr.globalStore
|
|
|
- tmp := endpoint{network: n}
|
|
|
- n.stopWatchCh = make(chan struct{})
|
|
|
- stopCh := n.stopWatchCh
|
|
|
- n.Unlock()
|
|
|
+func (c *controller) unWatchSvcRecord(ep *endpoint) {
|
|
|
+ c.unWatchCh <- ep
|
|
|
+}
|
|
|
|
|
|
- endpointKey := datastore.Key(tmp.KeyPrefix()...)
|
|
|
- if err := ensureKeys(endpointKey, cs); err != nil {
|
|
|
- return fmt.Errorf("failed to ensure if the endpoint keys are valid and present in store: %v", err)
|
|
|
- }
|
|
|
- epPairs, err := cs.KVStore().WatchTree(endpointKey, stopCh)
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
- go func() {
|
|
|
- for {
|
|
|
- select {
|
|
|
- case <-stopCh:
|
|
|
- return
|
|
|
- case eps := <-epPairs:
|
|
|
- n.Lock()
|
|
|
- tmpview := endpointTable{}
|
|
|
- lview := n.endpoints
|
|
|
- n.Unlock()
|
|
|
- for k, v := range lview {
|
|
|
- if v.network.isGlobalScoped() {
|
|
|
- tmpview[k] = v
|
|
|
- }
|
|
|
+func (c *controller) networkWatchLoop(nw *netWatch, ep *endpoint, nCh <-chan datastore.KVObject) {
|
|
|
+ for {
|
|
|
+ select {
|
|
|
+ case <-nw.stopCh:
|
|
|
+ return
|
|
|
+ case o := <-nCh:
|
|
|
+ n := o.(*network)
|
|
|
+
|
|
|
+ epl, err := n.getEndpointsFromStore()
|
|
|
+ if err != nil {
|
|
|
+ break
|
|
|
+ }
|
|
|
+
|
|
|
+ c.Lock()
|
|
|
+ var addEp []*endpoint
|
|
|
+
|
|
|
+ delEpMap := make(map[string]*endpoint)
|
|
|
+ for k, v := range nw.remoteEps {
|
|
|
+ delEpMap[k] = v
|
|
|
+ }
|
|
|
+
|
|
|
+ for _, lEp := range epl {
|
|
|
+ if _, ok := nw.localEps[lEp.ID()]; ok {
|
|
|
+ continue
|
|
|
}
|
|
|
- n.ctrlr.processEndpointsUpdate(eps, &tmpview)
|
|
|
- // Delete processing
|
|
|
- for k := range tmpview {
|
|
|
- n.Lock()
|
|
|
- existing, ok := n.endpoints[k]
|
|
|
- n.Unlock()
|
|
|
- if !ok {
|
|
|
- continue
|
|
|
- }
|
|
|
- tmp := endpoint{}
|
|
|
- if err := cs.GetObject(datastore.Key(existing.Key()...), &tmp); err != datastore.ErrKeyNotFound {
|
|
|
- continue
|
|
|
- }
|
|
|
- if err := existing.deleteEndpoint(); err != nil {
|
|
|
- log.Debugf("Delete failed %s: %s", existing.name, err)
|
|
|
- }
|
|
|
+
|
|
|
+ if _, ok := nw.remoteEps[lEp.ID()]; ok {
|
|
|
+ delete(delEpMap, lEp.ID())
|
|
|
+ continue
|
|
|
}
|
|
|
+
|
|
|
+ nw.remoteEps[lEp.ID()] = lEp
|
|
|
+ addEp = append(addEp, lEp)
|
|
|
+
|
|
|
+ }
|
|
|
+ c.Unlock()
|
|
|
+
|
|
|
+ for _, lEp := range addEp {
|
|
|
+ ep.getNetwork().updateSvcRecord(lEp, c.getLocalEps(nw), true)
|
|
|
}
|
|
|
- }
|
|
|
- }()
|
|
|
- return nil
|
|
|
-}
|
|
|
|
|
|
-func (n *network) stopWatch() {
|
|
|
- n.Lock()
|
|
|
- if n.stopWatchCh != nil {
|
|
|
- close(n.stopWatchCh)
|
|
|
- n.stopWatchCh = nil
|
|
|
+ for _, lEp := range delEpMap {
|
|
|
+ ep.getNetwork().updateSvcRecord(lEp, c.getLocalEps(nw), false)
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
- n.Unlock()
|
|
|
}
|
|
|
|
|
|
-func (c *controller) processNetworkUpdate(nws []*store.KVPair, prune *networkTable) {
|
|
|
- for _, kve := range nws {
|
|
|
- var n network
|
|
|
- err := json.Unmarshal(kve.Value, &n)
|
|
|
- if err != nil {
|
|
|
- log.Error(err)
|
|
|
- continue
|
|
|
- }
|
|
|
- if prune != nil {
|
|
|
- delete(*prune, n.id)
|
|
|
- }
|
|
|
- n.SetIndex(kve.LastIndex)
|
|
|
+func (c *controller) processEndpointCreate(nmap map[string]*netWatch, ep *endpoint) {
|
|
|
+ c.Lock()
|
|
|
+ nw, ok := nmap[ep.getNetwork().ID()]
|
|
|
+ c.Unlock()
|
|
|
+
|
|
|
+ if ok {
|
|
|
+ // Update the svc db for the local endpoint join right away
|
|
|
+ ep.getNetwork().updateSvcRecord(ep, c.getLocalEps(nw), true)
|
|
|
+
|
|
|
c.Lock()
|
|
|
- existing, ok := c.networks[n.id]
|
|
|
+ nw.localEps[ep.ID()] = ep
|
|
|
c.Unlock()
|
|
|
- if ok {
|
|
|
- existing.Lock()
|
|
|
- // Skip existing network update
|
|
|
- if existing.dbIndex != n.Index() {
|
|
|
- // Can't use SetIndex() since existing is locked.
|
|
|
- existing.dbIndex = n.Index()
|
|
|
- existing.dbExists = true
|
|
|
- existing.endpointCnt = n.endpointCnt
|
|
|
- }
|
|
|
- existing.Unlock()
|
|
|
- continue
|
|
|
- }
|
|
|
-
|
|
|
- if err = c.newNetworkFromStore(&n); err != nil {
|
|
|
- log.Error(err)
|
|
|
- }
|
|
|
+ return
|
|
|
}
|
|
|
-}
|
|
|
|
|
|
-func (c *controller) processEndpointUpdate(ep *endpoint) bool {
|
|
|
- nw := ep.network
|
|
|
- if nw == nil {
|
|
|
- return true
|
|
|
+ nw = &netWatch{
|
|
|
+ localEps: make(map[string]*endpoint),
|
|
|
+ remoteEps: make(map[string]*endpoint),
|
|
|
}
|
|
|
- nw.Lock()
|
|
|
- id := nw.id
|
|
|
- nw.Unlock()
|
|
|
+
|
|
|
+ // Update the svc db for the local endpoint join right away
|
|
|
+ // Do this before adding this ep to localEps so that we don't
|
|
|
+ // try to update this ep's container's svc records
|
|
|
+ ep.getNetwork().updateSvcRecord(ep, c.getLocalEps(nw), true)
|
|
|
|
|
|
c.Lock()
|
|
|
- n, ok := c.networks[id]
|
|
|
+ nw.localEps[ep.ID()] = ep
|
|
|
+ nmap[ep.getNetwork().ID()] = nw
|
|
|
+ nw.stopCh = make(chan struct{})
|
|
|
c.Unlock()
|
|
|
- if !ok {
|
|
|
- return true
|
|
|
- }
|
|
|
- existing, _ := n.EndpointByID(ep.id)
|
|
|
- if existing == nil {
|
|
|
- return true
|
|
|
- }
|
|
|
|
|
|
- ee := existing.(*endpoint)
|
|
|
- ee.Lock()
|
|
|
- if ee.dbIndex != ep.Index() {
|
|
|
- // Can't use SetIndex() because ee is locked.
|
|
|
- ee.dbIndex = ep.Index()
|
|
|
- ee.dbExists = true
|
|
|
- ee.sandboxID = ep.sandboxID
|
|
|
+ store := c.getStore(ep.getNetwork().DataScope())
|
|
|
+ if store == nil {
|
|
|
+ return
|
|
|
}
|
|
|
- ee.Unlock()
|
|
|
|
|
|
- return false
|
|
|
-}
|
|
|
+ if !store.Watchable() {
|
|
|
+ return
|
|
|
+ }
|
|
|
|
|
|
-func ensureKeys(key string, cs datastore.DataStore) error {
|
|
|
- exists, err := cs.KVStore().Exists(key)
|
|
|
+ ch, err := store.Watch(ep.getNetwork(), nw.stopCh)
|
|
|
if err != nil {
|
|
|
- return err
|
|
|
+ log.Warnf("Error creating watch for network: %v", err)
|
|
|
+ return
|
|
|
}
|
|
|
- if exists {
|
|
|
- return nil
|
|
|
- }
|
|
|
- return cs.KVStore().Put(key, []byte{}, nil)
|
|
|
-}
|
|
|
|
|
|
-func (c *controller) getLocalStoreConfig(cfg *config.Config) *config.DatastoreCfg {
|
|
|
- if cfg != nil && cfg.LocalStore.Client.Provider != "" && cfg.LocalStore.Client.Address != "" {
|
|
|
- return &cfg.LocalStore
|
|
|
- }
|
|
|
- return &defaultLocalStoreConfig
|
|
|
+ go c.networkWatchLoop(nw, ep, ch)
|
|
|
}
|
|
|
|
|
|
-func (c *controller) getDataStore(dataScope datastore.DataScope) (dataStore datastore.DataStore) {
|
|
|
+func (c *controller) processEndpointDelete(nmap map[string]*netWatch, ep *endpoint) {
|
|
|
c.Lock()
|
|
|
- if dataScope == datastore.GlobalScope {
|
|
|
- dataStore = c.globalStore
|
|
|
- } else if dataScope == datastore.LocalScope {
|
|
|
- dataStore = c.localStore
|
|
|
+ nw, ok := nmap[ep.getNetwork().ID()]
|
|
|
+
|
|
|
+ if ok {
|
|
|
+ delete(nw.localEps, ep.ID())
|
|
|
+ c.Unlock()
|
|
|
+
|
|
|
+ // Update the svc db about local endpoint leave right away
|
|
|
+ // Do this after we remove this ep from localEps so that we
|
|
|
+ // don't try to remove this svc record from this ep's container.
|
|
|
+ ep.getNetwork().updateSvcRecord(ep, c.getLocalEps(nw), false)
|
|
|
+
|
|
|
+ c.Lock()
|
|
|
+ if len(nw.localEps) == 0 {
|
|
|
+ close(nw.stopCh)
|
|
|
+ delete(nmap, ep.getNetwork().ID())
|
|
|
+ }
|
|
|
}
|
|
|
c.Unlock()
|
|
|
- return
|
|
|
}
|
|
|
|
|
|
-func (c *controller) processEndpointsUpdate(eps []*store.KVPair, prune *endpointTable) {
|
|
|
- for _, epe := range eps {
|
|
|
- var ep endpoint
|
|
|
- err := json.Unmarshal(epe.Value, &ep)
|
|
|
- if err != nil {
|
|
|
- log.Error(err)
|
|
|
- continue
|
|
|
- }
|
|
|
- if prune != nil {
|
|
|
- delete(*prune, ep.id)
|
|
|
- }
|
|
|
- ep.SetIndex(epe.LastIndex)
|
|
|
- if nid, err := ep.networkIDFromKey(epe.Key); err != nil {
|
|
|
- log.Error(err)
|
|
|
- continue
|
|
|
- } else {
|
|
|
- if n, err := c.NetworkByID(nid); err != nil {
|
|
|
- log.Error(err)
|
|
|
- continue
|
|
|
- } else {
|
|
|
- ep.network = n.(*network)
|
|
|
- }
|
|
|
- }
|
|
|
- if c.processEndpointUpdate(&ep) {
|
|
|
- err = c.newEndpointFromStore(epe.Key, &ep)
|
|
|
- if err != nil {
|
|
|
- log.Error(err)
|
|
|
- }
|
|
|
+func (c *controller) watchLoop(nmap map[string]*netWatch) {
|
|
|
+ for {
|
|
|
+ select {
|
|
|
+ case ep := <-c.watchCh:
|
|
|
+ c.processEndpointCreate(nmap, ep)
|
|
|
+ case ep := <-c.unWatchCh:
|
|
|
+ c.processEndpointDelete(nmap, ep)
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+func (c *controller) startWatch() {
|
|
|
+ c.watchCh = make(chan *endpoint)
|
|
|
+ c.unWatchCh = make(chan *endpoint)
|
|
|
+ nmap := make(map[string]*netWatch)
|
|
|
+
|
|
|
+ go c.watchLoop(nmap)
|
|
|
+}
|