diff --git a/libnetwork/controller.go b/libnetwork/controller.go index 4fa7168ef2..cdc547e903 100644 --- a/libnetwork/controller.go +++ b/libnetwork/controller.go @@ -91,7 +91,7 @@ type Controller struct { ipamRegistry drvregistry.IPAMs sandboxes sandboxTable cfg *config.Config - store datastore.DataStore + store *datastore.Store extKeyListener net.Listener watchCh chan *Endpoint unWatchCh chan *Endpoint diff --git a/libnetwork/datastore/cache.go b/libnetwork/datastore/cache.go index 61bc67e8ac..4effdfea23 100644 --- a/libnetwork/datastore/cache.go +++ b/libnetwork/datastore/cache.go @@ -13,10 +13,10 @@ type kvMap map[string]KVObject type cache struct { sync.Mutex kmm map[string]kvMap - ds *datastore + ds *Store } -func newCache(ds *datastore) *cache { +func newCache(ds *Store) *cache { return &cache{kmm: make(map[string]kvMap), ds: ds} } diff --git a/libnetwork/datastore/datastore.go b/libnetwork/datastore/datastore.go index 6af9f3bc0b..a431265068 100644 --- a/libnetwork/datastore/datastore.go +++ b/libnetwork/datastore/datastore.go @@ -2,7 +2,6 @@ package datastore import ( "fmt" - "reflect" "strings" "sync" "time" @@ -12,42 +11,20 @@ import ( "github.com/docker/docker/libnetwork/types" ) -// DataStore exported -type DataStore interface { - // GetObject gets data from datastore and unmarshals to the specified object - GetObject(key string, o KVObject) error - // PutObjectAtomic provides an atomic add and update operation for a Record - PutObjectAtomic(kvObject KVObject) error - // DeleteObjectAtomic performs an atomic delete operation - DeleteObjectAtomic(kvObject KVObject) error - // List returns of a list of KVObjects belonging to the parent - // key. The caller must pass a KVObject of the same type as - // the objects that need to be listed - List(string, KVObject) ([]KVObject, error) - // Map returns a Map of KVObjects - Map(key string, kvObject KVObject) (map[string]KVObject, error) - // Scope returns the scope of the store - Scope() string - // KVStore returns access to the KV Store - KVStore() store.Store - // Close closes the data store - Close() -} - // ErrKeyModified is raised for an atomic update when the update is working on a stale state var ( ErrKeyModified = store.ErrKeyModified ErrKeyNotFound = store.ErrKeyNotFound ) -type datastore struct { +type Store struct { mu sync.Mutex scope string store store.Store cache *cache } -// KVObject is Key/Value interface used by objects to be part of the DataStore +// KVObject is Key/Value interface used by objects to be part of the Store. type KVObject interface { // Key method lets an object provide the Key to be used in KV Store Key() []string @@ -61,7 +38,7 @@ type KVObject interface { Index() uint64 // SetIndex method allows the datastore to store the latest DB Index into the object SetIndex(uint64) - // True if the object exists in the datastore, false if it hasn't been stored yet. + // Exists returns true if the object exists in the datastore, false if it hasn't been stored yet. // When SetIndex() is called, the object has been stored. Exists() bool // DataScope indicates the storage scope of the KV object @@ -159,19 +136,8 @@ func Key(key ...string) string { return b.String() } -// ParseKey provides convenient method to unpack the key to complement the Key function -func ParseKey(key string) ([]string, error) { - chain := strings.Split(strings.Trim(key, "/"), "/") - - // The key must at least be equal to the rootChain in order to be considered as valid - if len(chain) <= len(rootChain) || !reflect.DeepEqual(chain[0:len(rootChain)], rootChain) { - return nil, types.BadRequestErrorf("invalid Key : %s", key) - } - return chain[len(rootChain):], nil -} - // newClient used to connect to KV Store -func newClient(kv string, addr string, config *store.Config) (DataStore, error) { +func newClient(kv string, addr string, config *store.Config) (*Store, error) { if config == nil { config = &store.Config{} } @@ -197,14 +163,14 @@ func newClient(kv string, addr string, config *store.Config) (DataStore, error) return nil, err } - ds := &datastore{scope: LocalScope, store: s} + ds := &Store{scope: LocalScope, store: s} ds.cache = newCache(ds) return ds, nil } -// NewDataStore creates a new instance of LibKV data store -func NewDataStore(cfg ScopeCfg) (DataStore, error) { +// New creates a new Store instance. +func New(cfg ScopeCfg) (*Store, error) { if cfg.Client.Provider == "" || cfg.Client.Address == "" { cfg = DefaultScope("") } @@ -212,8 +178,8 @@ func NewDataStore(cfg ScopeCfg) (DataStore, error) { return newClient(cfg.Client.Provider, cfg.Client.Address, cfg.Client.Config) } -// NewDataStoreFromConfig creates a new instance of LibKV data store starting from the datastore config data -func NewDataStoreFromConfig(dsc discoverapi.DatastoreConfigData) (DataStore, error) { +// FromConfig creates a new instance of LibKV data store starting from the datastore config data. +func FromConfig(dsc discoverapi.DatastoreConfigData) (*Store, error) { var ( ok bool sCfgP *store.Config @@ -224,15 +190,13 @@ func NewDataStoreFromConfig(dsc discoverapi.DatastoreConfigData) (DataStore, err return nil, fmt.Errorf("cannot parse store configuration: %v", dsc.Config) } - scopeCfg := ScopeCfg{ + ds, err := New(ScopeCfg{ Client: ScopeClientCfg{ Address: dsc.Address, Provider: dsc.Provider, Config: sCfgP, }, - } - - ds, err := NewDataStore(scopeCfg) + }) if err != nil { return nil, fmt.Errorf("failed to construct datastore client from datastore configuration %v: %v", dsc, err) } @@ -240,20 +204,23 @@ func NewDataStoreFromConfig(dsc discoverapi.DatastoreConfigData) (DataStore, err return ds, err } -func (ds *datastore) Close() { +// Close closes the data store. +func (ds *Store) Close() { ds.store.Close() } -func (ds *datastore) Scope() string { +// Scope returns the scope of the store. +func (ds *Store) Scope() string { return ds.scope } -func (ds *datastore) KVStore() store.Store { +// KVStore returns access to the KV Store. +func (ds *Store) KVStore() store.Store { return ds.store } -// PutObjectAtomic adds a new Record based on an object into the datastore -func (ds *datastore) PutObjectAtomic(kvObject KVObject) error { +// PutObjectAtomic provides an atomic add and update operation for a Record. +func (ds *Store) PutObjectAtomic(kvObject KVObject) error { var ( previous *store.KVPair pair *store.KVPair @@ -302,8 +269,8 @@ add_cache: return nil } -// GetObject returns a record matching the key -func (ds *datastore) GetObject(key string, o KVObject) error { +// GetObject gets data from the store and unmarshals to the specified object. +func (ds *Store) GetObject(key string, o KVObject) error { ds.mu.Lock() defer ds.mu.Unlock() @@ -326,7 +293,7 @@ func (ds *datastore) GetObject(key string, o KVObject) error { return nil } -func (ds *datastore) ensureParent(parent string) error { +func (ds *Store) ensureParent(parent string) error { exists, err := ds.store.Exists(parent) if err != nil { return err @@ -337,7 +304,9 @@ func (ds *datastore) ensureParent(parent string) error { return ds.store.Put(parent, []byte{}) } -func (ds *datastore) List(key string, kvObject KVObject) ([]KVObject, error) { +// List returns of a list of KVObjects belonging to the parent key. The caller +// must pass a KVObject of the same type as the objects that need to be listed. +func (ds *Store) List(key string, kvObject KVObject) ([]KVObject, error) { ds.mu.Lock() defer ds.mu.Unlock() @@ -356,7 +325,7 @@ func (ds *datastore) List(key string, kvObject KVObject) ([]KVObject, error) { return kvol, nil } -func (ds *datastore) iterateKVPairsFromStore(key string, kvObject KVObject, callback func(string, KVObject)) error { +func (ds *Store) iterateKVPairsFromStore(key string, kvObject KVObject, callback func(string, KVObject)) error { // Bail out right away if the kvObject does not implement KVConstructor ctor, ok := kvObject.(KVConstructor) if !ok { @@ -392,7 +361,8 @@ func (ds *datastore) iterateKVPairsFromStore(key string, kvObject KVObject, call return nil } -func (ds *datastore) Map(key string, kvObject KVObject) (map[string]KVObject, error) { +// Map returns a Map of KVObjects. +func (ds *Store) Map(key string, kvObject KVObject) (map[string]KVObject, error) { ds.mu.Lock() defer ds.mu.Unlock() @@ -408,8 +378,8 @@ func (ds *datastore) Map(key string, kvObject KVObject) (map[string]KVObject, er return kvol, nil } -// DeleteObjectAtomic performs atomic delete on a record -func (ds *datastore) DeleteObjectAtomic(kvObject KVObject) error { +// DeleteObjectAtomic performs atomic delete on a record. +func (ds *Store) DeleteObjectAtomic(kvObject KVObject) error { ds.mu.Lock() defer ds.mu.Unlock() diff --git a/libnetwork/datastore/datastore_test.go b/libnetwork/datastore/datastore_test.go index 873c7b459e..cc5a72634c 100644 --- a/libnetwork/datastore/datastore_test.go +++ b/libnetwork/datastore/datastore_test.go @@ -2,7 +2,6 @@ package datastore import ( "encoding/json" - "reflect" "testing" "github.com/docker/docker/libnetwork/options" @@ -11,9 +10,9 @@ import ( var dummyKey = "dummy" -// NewCustomDataStore can be used by other Tests in order to use custom datastore -func NewTestDataStore() DataStore { - return &datastore{scope: LocalScope, store: NewMockStore()} +// NewTestDataStore can be used by other Tests in order to use custom datastore +func NewTestDataStore() *Store { + return &Store{scope: LocalScope, store: NewMockStore()} } func TestKey(t *testing.T) { @@ -24,25 +23,13 @@ func TestKey(t *testing.T) { } } -func TestParseKey(t *testing.T) { - keySlice, err := ParseKey("/docker/network/v1.0/hello/world/") - if err != nil { - t.Fatal(err) - } - eKey := []string{"hello", "world"} - if len(keySlice) < 2 || !reflect.DeepEqual(eKey, keySlice) { - t.Fatalf("unexpected unkey : %s", keySlice) - } -} - func TestInvalidDataStore(t *testing.T) { - config := ScopeCfg{ + _, err := New(ScopeCfg{ Client: ScopeClientCfg{ Provider: "invalid", Address: "localhost:8500", }, - } - _, err := NewDataStore(config) + }) if err == nil { t.Fatal("Invalid Datastore connection configuration must result in a failure") } diff --git a/libnetwork/datastore/mock_store.go b/libnetwork/datastore/mockstore_test.go similarity index 92% rename from libnetwork/datastore/mock_store.go rename to libnetwork/datastore/mockstore_test.go index 9e7a0bb84b..39db246ed8 100644 --- a/libnetwork/datastore/mock_store.go +++ b/libnetwork/datastore/mockstore_test.go @@ -7,9 +7,6 @@ import ( "github.com/docker/docker/libnetwork/types" ) -// ErrNotImplemented exported -var ErrNotImplemented = errors.New("Functionality not implemented") - // MockData exported type MockData struct { Data []byte @@ -23,8 +20,7 @@ type MockStore struct { // NewMockStore creates a Map backed Datastore that is useful for mocking func NewMockStore() *MockStore { - db := make(map[string]*MockData) - return &MockStore{db} + return &MockStore{db: make(map[string]*MockData)} } // Get the value at "key", returns the last modified index @@ -56,7 +52,7 @@ func (s *MockStore) Exists(key string) (bool, error) { // List gets a range of values at "directory" func (s *MockStore) List(prefix string) ([]*store.KVPair, error) { - return nil, ErrNotImplemented + return nil, errors.New("not implemented") } // AtomicPut put a value at "key" if the key has not been diff --git a/libnetwork/drivers/bridge/bridge.go b/libnetwork/drivers/bridge/bridge.go index 02c81a2a6c..ffc68e125e 100644 --- a/libnetwork/drivers/bridge/bridge.go +++ b/libnetwork/drivers/bridge/bridge.go @@ -153,7 +153,7 @@ type driver struct { isolationChain1V6 *iptables.ChainInfo isolationChain2V6 *iptables.ChainInfo networks map[string]*bridgeNetwork - store datastore.DataStore + store *datastore.Store nlh *netlink.Handle configNetwork sync.Mutex portAllocator *portallocator.PortAllocator // Overridable for tests. diff --git a/libnetwork/drivers/bridge/bridge_store.go b/libnetwork/drivers/bridge/bridge_store.go index 4735a360cb..216a2b41fd 100644 --- a/libnetwork/drivers/bridge/bridge_store.go +++ b/libnetwork/drivers/bridge/bridge_store.go @@ -30,7 +30,7 @@ func (d *driver) initStore(option map[string]interface{}) error { if !ok { return types.InternalErrorf("incorrect data in datastore configuration: %v", data) } - d.store, err = datastore.NewDataStoreFromConfig(dsc) + d.store, err = datastore.FromConfig(dsc) if err != nil { return types.InternalErrorf("bridge driver failed to initialize data store: %v", err) } diff --git a/libnetwork/drivers/ipvlan/ipvlan.go b/libnetwork/drivers/ipvlan/ipvlan.go index 84d7822cf3..121ac814ce 100644 --- a/libnetwork/drivers/ipvlan/ipvlan.go +++ b/libnetwork/drivers/ipvlan/ipvlan.go @@ -40,7 +40,7 @@ type driver struct { networks networkTable sync.Once sync.Mutex - store datastore.DataStore + store *datastore.Store } type endpoint struct { diff --git a/libnetwork/drivers/ipvlan/ipvlan_store.go b/libnetwork/drivers/ipvlan/ipvlan_store.go index 14b57ea4be..cf0da80fa5 100644 --- a/libnetwork/drivers/ipvlan/ipvlan_store.go +++ b/libnetwork/drivers/ipvlan/ipvlan_store.go @@ -50,7 +50,7 @@ func (d *driver) initStore(option map[string]interface{}) error { if !ok { return types.InternalErrorf("incorrect data in datastore configuration: %v", data) } - d.store, err = datastore.NewDataStoreFromConfig(dsc) + d.store, err = datastore.FromConfig(dsc) if err != nil { return types.InternalErrorf("ipvlan driver failed to initialize data store: %v", err) } diff --git a/libnetwork/drivers/macvlan/macvlan.go b/libnetwork/drivers/macvlan/macvlan.go index a5c9121835..d9a7f3ba27 100644 --- a/libnetwork/drivers/macvlan/macvlan.go +++ b/libnetwork/drivers/macvlan/macvlan.go @@ -34,7 +34,7 @@ type driver struct { networks networkTable sync.Once sync.Mutex - store datastore.DataStore + store *datastore.Store } type endpoint struct { diff --git a/libnetwork/drivers/macvlan/macvlan_store.go b/libnetwork/drivers/macvlan/macvlan_store.go index bd4aecf356..924c5d750b 100644 --- a/libnetwork/drivers/macvlan/macvlan_store.go +++ b/libnetwork/drivers/macvlan/macvlan_store.go @@ -49,7 +49,7 @@ func (d *driver) initStore(option map[string]interface{}) error { if !ok { return types.InternalErrorf("incorrect data in datastore configuration: %v", data) } - d.store, err = datastore.NewDataStoreFromConfig(dsc) + d.store, err = datastore.FromConfig(dsc) if err != nil { return types.InternalErrorf("macvlan driver failed to initialize data store: %v", err) } diff --git a/libnetwork/drivers/windows/windows.go b/libnetwork/drivers/windows/windows.go index e18cc8a83b..6174d97d0c 100644 --- a/libnetwork/drivers/windows/windows.go +++ b/libnetwork/drivers/windows/windows.go @@ -101,7 +101,7 @@ type hnsNetwork struct { type driver struct { name string networks map[string]*hnsNetwork - store datastore.DataStore + store *datastore.Store sync.Mutex } diff --git a/libnetwork/drivers/windows/windows_store.go b/libnetwork/drivers/windows/windows_store.go index fb453b9005..b2a6bcbd0b 100644 --- a/libnetwork/drivers/windows/windows_store.go +++ b/libnetwork/drivers/windows/windows_store.go @@ -27,7 +27,7 @@ func (d *driver) initStore(option map[string]interface{}) error { if !ok { return types.InternalErrorf("incorrect data in datastore configuration: %v", data) } - d.store, err = datastore.NewDataStoreFromConfig(dsc) + d.store, err = datastore.FromConfig(dsc) if err != nil { return types.InternalErrorf("windows driver failed to initialize data store: %v", err) } diff --git a/libnetwork/store.go b/libnetwork/store.go index 119a51731c..153dc543f3 100644 --- a/libnetwork/store.go +++ b/libnetwork/store.go @@ -24,7 +24,7 @@ func (c *Controller) initStores() error { return nil } var err error - c.store, err = datastore.NewDataStore(c.cfg.Scope) + c.store, err = datastore.New(c.cfg.Scope) if err != nil { return err } @@ -39,7 +39,7 @@ func (c *Controller) closeStores() { } } -func (c *Controller) getStore() datastore.DataStore { +func (c *Controller) getStore() *datastore.Store { c.mu.Lock() defer c.mu.Unlock()