diff --git a/libnetwork/bitseq/store.go b/libnetwork/bitseq/store.go index a6550f415e..8012a413d2 100644 --- a/libnetwork/bitseq/store.go +++ b/libnetwork/bitseq/store.go @@ -70,6 +70,11 @@ func (h *Handle) Exists() bool { return h.dbExists } +// Skip provides a way for a KV Object to avoid persisting it in the KV Store +func (h *Handle) Skip() bool { + return false +} + // DataScope method returns the storage scope of the datastore func (h *Handle) DataScope() datastore.DataScope { return datastore.GlobalScope diff --git a/libnetwork/controller.go b/libnetwork/controller.go index f834b7b370..dbb4a0c9f6 100644 --- a/libnetwork/controller.go +++ b/libnetwork/controller.go @@ -248,6 +248,7 @@ func (c *controller) NewNetwork(networkType, name string, options ...NetworkOpti id: stringid.GenerateRandomID(), ctrlr: c, endpoints: endpointTable{}, + persist: true, } network.processOptions(options...) diff --git a/libnetwork/datastore/datastore.go b/libnetwork/datastore/datastore.go index 07a0df5c6b..927b67d23e 100644 --- a/libnetwork/datastore/datastore.go +++ b/libnetwork/datastore/datastore.go @@ -61,6 +61,8 @@ type KV interface { Exists() bool // DataScope indicates the storage scope of the KV object DataScope() DataScope + // Skip provides a way for a KV Object to avoid persisting it in the KV Store + Skip() bool } // DataScope indicates the storage scope diff --git a/libnetwork/datastore/datastore_test.go b/libnetwork/datastore/datastore_test.go index fe2befd5ab..59290cbbe7 100644 --- a/libnetwork/datastore/datastore_test.go +++ b/libnetwork/datastore/datastore_test.go @@ -122,6 +122,7 @@ type dummyObject struct { ID string DBIndex uint64 DBExists bool + SkipSave bool ReturnValue bool } @@ -162,6 +163,10 @@ func (n *dummyObject) Exists() bool { return n.DBExists } +func (n *dummyObject) Skip() bool { + return n.SkipSave +} + func (n *dummyObject) DataScope() DataScope { return LocalScope } @@ -194,6 +199,7 @@ type recStruct struct { Dict map[string]string `kv:"iterative"` DBIndex uint64 DBExists bool + SkipSave bool } func (r *recStruct) Key() []string { @@ -224,6 +230,10 @@ func (r *recStruct) Exists() bool { return r.DBExists } +func (r *recStruct) Skip() bool { + return r.SkipSave +} + func dummyKVObject(id string, retValue bool) *dummyObject { cDict := make(map[string]string) cDict["foo"] = "bar" @@ -232,13 +242,14 @@ func dummyKVObject(id string, retValue bool) *dummyObject { Name: "testNw", NetworkType: "bridge", EnableIPv6: true, - Rec: &recStruct{"gen", 5, cDict, 0, false}, + Rec: &recStruct{"gen", 5, cDict, 0, false, false}, ID: id, DBIndex: 0, ReturnValue: retValue, - DBExists: false} + DBExists: false, + SkipSave: false} generic := make(map[string]interface{}) - generic["label1"] = &recStruct{"value1", 1, cDict, 0, false} + generic["label1"] = &recStruct{"value1", 1, cDict, 0, false, false} generic["label2"] = "subnet=10.1.1.0/16" n.Generic = generic return &n diff --git a/libnetwork/drivers/overlay/ov_network.go b/libnetwork/drivers/overlay/ov_network.go index 55d8edba50..94bd9bbbfb 100644 --- a/libnetwork/drivers/overlay/ov_network.go +++ b/libnetwork/drivers/overlay/ov_network.go @@ -297,6 +297,10 @@ func (n *network) Exists() bool { return n.dbExists } +func (n *network) Skip() bool { + return false +} + func (n *network) SetValue(value []byte) error { var vni uint32 err := json.Unmarshal(value, &vni) diff --git a/libnetwork/endpoint.go b/libnetwork/endpoint.go index 6faa71dbbc..b6709ecc75 100644 --- a/libnetwork/endpoint.go +++ b/libnetwork/endpoint.go @@ -173,6 +173,10 @@ func (ep *endpoint) Exists() bool { return ep.dbExists } +func (ep *endpoint) Skip() bool { + return ep.getNetwork().Skip() +} + func (ep *endpoint) processOptions(options ...EndpointOption) { ep.Lock() defer ep.Unlock() diff --git a/libnetwork/ipam/store.go b/libnetwork/ipam/store.go index 2e204980be..8794a3d194 100644 --- a/libnetwork/ipam/store.go +++ b/libnetwork/ipam/store.go @@ -111,6 +111,11 @@ func (a *Allocator) Exists() bool { return a.dbExists } +// Skip provides a way for a KV Object to avoid persisting it in the KV Store +func (a *Allocator) Skip() bool { + return false +} + func (a *Allocator) watchForChanges() error { if a.store == nil { return nil diff --git a/libnetwork/network.go b/libnetwork/network.go index 855a365e1f..ea7d4ea600 100644 --- a/libnetwork/network.go +++ b/libnetwork/network.go @@ -68,6 +68,7 @@ type network struct { dbIndex uint64 svcRecords svcMap dbExists bool + persist bool stopWatchCh chan struct{} dataScope datastore.DataScope sync.Mutex @@ -141,6 +142,12 @@ func (n *network) Exists() bool { return n.dbExists } +func (n *network) Skip() bool { + n.Lock() + defer n.Unlock() + return !n.persist +} + func (n *network) DataScope() datastore.DataScope { n.Lock() defer n.Unlock() @@ -174,6 +181,7 @@ func (n *network) MarshalJSON() ([]byte, error) { netMap["endpointCnt"] = n.endpointCnt netMap["enableIPv6"] = n.enableIPv6 netMap["generic"] = n.generic + netMap["persist"] = n.persist return json.Marshal(netMap) } @@ -191,6 +199,9 @@ func (n *network) UnmarshalJSON(b []byte) (err error) { if netMap["generic"] != nil { n.generic = netMap["generic"].(map[string]interface{}) } + if netMap["persist"] != nil { + n.persist = netMap["persist"].(bool) + } return nil } @@ -210,6 +221,13 @@ func NetworkOptionGeneric(generic map[string]interface{}) NetworkOption { } } +// NetworkOptionPersist returns an option setter to set persistence policy for a network +func NetworkOptionPersist(persist bool) NetworkOption { + return func(n *network) { + n.persist = persist + } +} + func (n *network) processOptions(options ...NetworkOption) { for _, opt := range options { if opt != nil { diff --git a/libnetwork/store.go b/libnetwork/store.go index 4c2bcd58b7..960ec7ff2c 100644 --- a/libnetwork/store.go +++ b/libnetwork/store.go @@ -110,6 +110,9 @@ func (c *controller) newEndpointFromStore(key string, ep *endpoint) error { } func (c *controller) updateToStore(kvObject datastore.KV) error { + if kvObject.Skip() { + return nil + } cs := c.getDataStore(kvObject.DataScope()) if cs == nil { log.Debugf("datastore not initialized. kv object %s is not added to the store", datastore.Key(kvObject.Key()...)) @@ -120,6 +123,9 @@ func (c *controller) updateToStore(kvObject datastore.KV) error { } func (c *controller) deleteFromStore(kvObject datastore.KV) error { + if kvObject.Skip() { + return nil + } cs := c.getDataStore(kvObject.DataScope()) if cs == nil { log.Debugf("datastore not initialized. kv object %s is not deleted from datastore", datastore.Key(kvObject.Key()...)) @@ -188,7 +194,7 @@ func (c *controller) watchNetworks() error { } func (n *network) watchEndpoints() error { - if !n.ctrlr.validateGlobalStoreConfig() { + if n.Skip() || !n.ctrlr.validateGlobalStoreConfig() { return nil } diff --git a/libnetwork/store_test.go b/libnetwork/store_test.go index 0c9ad943cd..574360b1da 100644 --- a/libnetwork/store_test.go +++ b/libnetwork/store_test.go @@ -79,6 +79,33 @@ func testLocalBackend(t *testing.T, provider, url string, storeConfig *store.Con } } +func TestNoPersist(t *testing.T) { + cfgOptions, err := OptionBoltdbWithRandomDBFile() + if err != nil { + t.Fatalf("Error creating random boltdb file : %v", err) + } + ctrl, err := New(cfgOptions...) + if err != nil { + t.Fatalf("Error new controller: %v", err) + } + nw, err := ctrl.NewNetwork("host", "host", NetworkOptionPersist(false)) + if err != nil { + t.Fatalf("Error creating default \"host\" network: %v", err) + } + ep, err := nw.CreateEndpoint("newendpoint", []EndpointOption{}...) + if err != nil { + t.Fatalf("Error creating endpoint: %v", err) + } + store := ctrl.(*controller).localStore.KVStore() + if exists, _ := store.Exists(datastore.Key(datastore.NetworkKeyPrefix, string(nw.ID()))); exists { + t.Fatalf("Network with persist=false should not be stored in KV Store") + } + if exists, _ := store.Exists(datastore.Key([]string{datastore.EndpointKeyPrefix, string(nw.ID()), string(ep.ID())}...)); exists { + t.Fatalf("Endpoint in Network with persist=false should not be stored in KV Store") + } + store.Close() +} + // OptionBoltdbWithRandomDBFile function returns a random dir for local store backend func OptionBoltdbWithRandomDBFile() ([]config.Option, error) { tmp, err := ioutil.TempFile("", "libnetwork-")