github.com/Heebron/moby@v0.0.0-20221111184709-6eab4f55faf7/libnetwork/datastore/datastore.go (about)

     1  package datastore
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"reflect"
     7  	"strings"
     8  	"sync"
     9  	"time"
    10  
    11  	"github.com/docker/docker/libnetwork/discoverapi"
    12  	"github.com/docker/docker/libnetwork/types"
    13  	"github.com/docker/libkv"
    14  	"github.com/docker/libkv/store"
    15  )
    16  
    17  // DataStore exported
    18  type DataStore interface {
    19  	// GetObject gets data from datastore and unmarshals to the specified object
    20  	GetObject(key string, o KVObject) error
    21  	// PutObject adds a new Record based on an object into the datastore
    22  	PutObject(kvObject KVObject) error
    23  	// PutObjectAtomic provides an atomic add and update operation for a Record
    24  	PutObjectAtomic(kvObject KVObject) error
    25  	// DeleteObject deletes a record
    26  	DeleteObject(kvObject KVObject) error
    27  	// DeleteObjectAtomic performs an atomic delete operation
    28  	DeleteObjectAtomic(kvObject KVObject) error
    29  	// DeleteTree deletes a record
    30  	DeleteTree(kvObject KVObject) error
    31  	// Watchable returns whether the store is watchable or not
    32  	Watchable() bool
    33  	// Watch for changes on a KVObject
    34  	Watch(kvObject KVObject, stopCh <-chan struct{}) (<-chan KVObject, error)
    35  	// RestartWatch retriggers stopped Watches
    36  	RestartWatch()
    37  	// Active returns if the store is active
    38  	Active() bool
    39  	// List returns of a list of KVObjects belonging to the parent
    40  	// key. The caller must pass a KVObject of the same type as
    41  	// the objects that need to be listed
    42  	List(string, KVObject) ([]KVObject, error)
    43  	// Map returns a Map of KVObjects
    44  	Map(key string, kvObject KVObject) (map[string]KVObject, error)
    45  	// Scope returns the scope of the store
    46  	Scope() string
    47  	// KVStore returns access to the KV Store
    48  	KVStore() store.Store
    49  	// Close closes the data store
    50  	Close()
    51  }
    52  
    53  // ErrKeyModified is raised for an atomic update when the update is working on a stale state
    54  var (
    55  	ErrKeyModified = store.ErrKeyModified
    56  	ErrKeyNotFound = store.ErrKeyNotFound
    57  )
    58  
    59  type datastore struct {
    60  	scope      string
    61  	store      store.Store
    62  	cache      *cache
    63  	watchCh    chan struct{}
    64  	active     bool
    65  	sequential bool
    66  	sync.Mutex
    67  }
    68  
    69  // KVObject is Key/Value interface used by objects to be part of the DataStore
    70  type KVObject interface {
    71  	// Key method lets an object provide the Key to be used in KV Store
    72  	Key() []string
    73  	// KeyPrefix method lets an object return immediate parent key that can be used for tree walk
    74  	KeyPrefix() []string
    75  	// Value method lets an object marshal its content to be stored in the KV store
    76  	Value() []byte
    77  	// SetValue is used by the datastore to set the object's value when loaded from the data store.
    78  	SetValue([]byte) error
    79  	// Index method returns the latest DB Index as seen by the object
    80  	Index() uint64
    81  	// SetIndex method allows the datastore to store the latest DB Index into the object
    82  	SetIndex(uint64)
    83  	// True if the object exists in the datastore, false if it hasn't been stored yet.
    84  	// When SetIndex() is called, the object has been stored.
    85  	Exists() bool
    86  	// DataScope indicates the storage scope of the KV object
    87  	DataScope() string
    88  	// Skip provides a way for a KV Object to avoid persisting it in the KV Store
    89  	Skip() bool
    90  }
    91  
    92  // KVConstructor interface defines methods which can construct a KVObject from another.
    93  type KVConstructor interface {
    94  	// New returns a new object which is created based on the
    95  	// source object
    96  	New() KVObject
    97  	// CopyTo deep copies the contents of the implementing object
    98  	// to the passed destination object
    99  	CopyTo(KVObject) error
   100  }
   101  
   102  // ScopeCfg represents Datastore configuration.
   103  type ScopeCfg struct {
   104  	Client ScopeClientCfg
   105  }
   106  
   107  // ScopeClientCfg represents Datastore Client-only mode configuration
   108  type ScopeClientCfg struct {
   109  	Provider string
   110  	Address  string
   111  	Config   *store.Config
   112  }
   113  
   114  const (
   115  	// LocalScope indicates to store the KV object in local datastore such as boltdb
   116  	LocalScope = "local"
   117  	// GlobalScope indicates to store the KV object in global datastore
   118  	GlobalScope = "global"
   119  	// SwarmScope is not indicating a datastore location. It is defined here
   120  	// along with the other two scopes just for consistency.
   121  	SwarmScope    = "swarm"
   122  	defaultPrefix = "/var/lib/docker/network/files"
   123  )
   124  
   125  const (
   126  	// NetworkKeyPrefix is the prefix for network key in the kv store
   127  	NetworkKeyPrefix = "network"
   128  	// EndpointKeyPrefix is the prefix for endpoint key in the kv store
   129  	EndpointKeyPrefix = "endpoint"
   130  )
   131  
   132  var (
   133  	defaultScopes = makeDefaultScopes()
   134  )
   135  
   136  func makeDefaultScopes() map[string]*ScopeCfg {
   137  	def := make(map[string]*ScopeCfg)
   138  	def[LocalScope] = &ScopeCfg{
   139  		Client: ScopeClientCfg{
   140  			Provider: string(store.BOLTDB),
   141  			Address:  defaultPrefix + "/local-kv.db",
   142  			Config: &store.Config{
   143  				Bucket:            "libnetwork",
   144  				ConnectionTimeout: time.Minute,
   145  			},
   146  		},
   147  	}
   148  
   149  	return def
   150  }
   151  
   152  var defaultRootChain = []string{"docker", "network", "v1.0"}
   153  var rootChain = defaultRootChain
   154  
   155  // DefaultScopes returns a map of default scopes and its config for clients to use.
   156  func DefaultScopes(dataDir string) map[string]*ScopeCfg {
   157  	if dataDir != "" {
   158  		defaultScopes[LocalScope].Client.Address = dataDir + "/network/files/local-kv.db"
   159  		return defaultScopes
   160  	}
   161  
   162  	defaultScopes[LocalScope].Client.Address = defaultPrefix + "/local-kv.db"
   163  	return defaultScopes
   164  }
   165  
   166  // IsValid checks if the scope config has valid configuration.
   167  func (cfg *ScopeCfg) IsValid() bool {
   168  	if cfg == nil ||
   169  		strings.TrimSpace(cfg.Client.Provider) == "" ||
   170  		strings.TrimSpace(cfg.Client.Address) == "" {
   171  		return false
   172  	}
   173  
   174  	return true
   175  }
   176  
   177  // Key provides convenient method to create a Key
   178  func Key(key ...string) string {
   179  	keychain := append(rootChain, key...)
   180  	str := strings.Join(keychain, "/")
   181  	return str + "/"
   182  }
   183  
   184  // ParseKey provides convenient method to unpack the key to complement the Key function
   185  func ParseKey(key string) ([]string, error) {
   186  	chain := strings.Split(strings.Trim(key, "/"), "/")
   187  
   188  	// The key must at least be equal to the rootChain in order to be considered as valid
   189  	if len(chain) <= len(rootChain) || !reflect.DeepEqual(chain[0:len(rootChain)], rootChain) {
   190  		return nil, types.BadRequestErrorf("invalid Key : %s", key)
   191  	}
   192  	return chain[len(rootChain):], nil
   193  }
   194  
   195  // newClient used to connect to KV Store
   196  func newClient(scope string, kv string, addr string, config *store.Config, cached bool) (DataStore, error) {
   197  
   198  	if cached && scope != LocalScope {
   199  		return nil, fmt.Errorf("caching supported only for scope %s", LocalScope)
   200  	}
   201  	sequential := false
   202  	if scope == LocalScope {
   203  		sequential = true
   204  	}
   205  
   206  	if config == nil {
   207  		config = &store.Config{}
   208  	}
   209  
   210  	var addrs []string
   211  
   212  	if kv == string(store.BOLTDB) {
   213  		// Parse file path
   214  		addrs = strings.Split(addr, ",")
   215  	} else {
   216  		// Parse URI
   217  		parts := strings.SplitN(addr, "/", 2)
   218  		addrs = strings.Split(parts[0], ",")
   219  
   220  		// Add the custom prefix to the root chain
   221  		if len(parts) == 2 {
   222  			rootChain = append([]string{parts[1]}, defaultRootChain...)
   223  		}
   224  	}
   225  
   226  	store, err := libkv.NewStore(store.Backend(kv), addrs, config)
   227  	if err != nil {
   228  		return nil, err
   229  	}
   230  
   231  	ds := &datastore{scope: scope, store: store, active: true, watchCh: make(chan struct{}), sequential: sequential}
   232  	if cached {
   233  		ds.cache = newCache(ds)
   234  	}
   235  
   236  	return ds, nil
   237  }
   238  
   239  // NewDataStore creates a new instance of LibKV data store
   240  func NewDataStore(scope string, cfg *ScopeCfg) (DataStore, error) {
   241  	if cfg == nil || cfg.Client.Provider == "" || cfg.Client.Address == "" {
   242  		c, ok := defaultScopes[scope]
   243  		if !ok || c.Client.Provider == "" || c.Client.Address == "" {
   244  			return nil, fmt.Errorf("unexpected scope %s without configuration passed", scope)
   245  		}
   246  
   247  		cfg = c
   248  	}
   249  
   250  	var cached bool
   251  	if scope == LocalScope {
   252  		cached = true
   253  	}
   254  
   255  	return newClient(scope, cfg.Client.Provider, cfg.Client.Address, cfg.Client.Config, cached)
   256  }
   257  
   258  // NewDataStoreFromConfig creates a new instance of LibKV data store starting from the datastore config data
   259  func NewDataStoreFromConfig(dsc discoverapi.DatastoreConfigData) (DataStore, error) {
   260  	var (
   261  		ok    bool
   262  		sCfgP *store.Config
   263  	)
   264  
   265  	sCfgP, ok = dsc.Config.(*store.Config)
   266  	if !ok && dsc.Config != nil {
   267  		return nil, fmt.Errorf("cannot parse store configuration: %v", dsc.Config)
   268  	}
   269  
   270  	scopeCfg := &ScopeCfg{
   271  		Client: ScopeClientCfg{
   272  			Address:  dsc.Address,
   273  			Provider: dsc.Provider,
   274  			Config:   sCfgP,
   275  		},
   276  	}
   277  
   278  	ds, err := NewDataStore(dsc.Scope, scopeCfg)
   279  	if err != nil {
   280  		return nil, fmt.Errorf("failed to construct datastore client from datastore configuration %v: %v", dsc, err)
   281  	}
   282  
   283  	return ds, err
   284  }
   285  
   286  func (ds *datastore) Close() {
   287  	ds.store.Close()
   288  }
   289  
   290  func (ds *datastore) Scope() string {
   291  	return ds.scope
   292  }
   293  
   294  func (ds *datastore) Active() bool {
   295  	return ds.active
   296  }
   297  
   298  func (ds *datastore) Watchable() bool {
   299  	return ds.scope != LocalScope
   300  }
   301  
   302  func (ds *datastore) Watch(kvObject KVObject, stopCh <-chan struct{}) (<-chan KVObject, error) {
   303  	sCh := make(chan struct{})
   304  
   305  	ctor, ok := kvObject.(KVConstructor)
   306  	if !ok {
   307  		return nil, fmt.Errorf("error watching object type %T, object does not implement KVConstructor interface", kvObject)
   308  	}
   309  
   310  	kvpCh, err := ds.store.Watch(Key(kvObject.Key()...), sCh)
   311  	if err != nil {
   312  		return nil, err
   313  	}
   314  
   315  	kvoCh := make(chan KVObject)
   316  
   317  	go func() {
   318  	retry_watch:
   319  		var err error
   320  
   321  		// Make sure to get a new instance of watch channel
   322  		ds.Lock()
   323  		watchCh := ds.watchCh
   324  		ds.Unlock()
   325  
   326  	loop:
   327  		for {
   328  			select {
   329  			case <-stopCh:
   330  				close(sCh)
   331  				return
   332  			case kvPair := <-kvpCh:
   333  				// If the backend KV store gets reset libkv's go routine
   334  				// for the watch can exit resulting in a nil value in
   335  				// channel.
   336  				if kvPair == nil {
   337  					ds.Lock()
   338  					ds.active = false
   339  					ds.Unlock()
   340  					break loop
   341  				}
   342  
   343  				dstO := ctor.New()
   344  
   345  				if err = dstO.SetValue(kvPair.Value); err != nil {
   346  					log.Printf("Could not unmarshal kvpair value = %s", string(kvPair.Value))
   347  					break
   348  				}
   349  
   350  				dstO.SetIndex(kvPair.LastIndex)
   351  				kvoCh <- dstO
   352  			}
   353  		}
   354  
   355  		// Wait on watch channel for a re-trigger when datastore becomes active
   356  		<-watchCh
   357  
   358  		kvpCh, err = ds.store.Watch(Key(kvObject.Key()...), sCh)
   359  		if err != nil {
   360  			log.Printf("Could not watch the key %s in store: %v", Key(kvObject.Key()...), err)
   361  		}
   362  
   363  		goto retry_watch
   364  	}()
   365  
   366  	return kvoCh, nil
   367  }
   368  
   369  func (ds *datastore) RestartWatch() {
   370  	ds.Lock()
   371  	defer ds.Unlock()
   372  
   373  	ds.active = true
   374  	watchCh := ds.watchCh
   375  	ds.watchCh = make(chan struct{})
   376  	close(watchCh)
   377  }
   378  
   379  func (ds *datastore) KVStore() store.Store {
   380  	return ds.store
   381  }
   382  
   383  // PutObjectAtomic adds a new Record based on an object into the datastore
   384  func (ds *datastore) PutObjectAtomic(kvObject KVObject) error {
   385  	var (
   386  		previous *store.KVPair
   387  		pair     *store.KVPair
   388  		err      error
   389  	)
   390  	if ds.sequential {
   391  		ds.Lock()
   392  		defer ds.Unlock()
   393  	}
   394  
   395  	if kvObject == nil {
   396  		return types.BadRequestErrorf("invalid KV Object : nil")
   397  	}
   398  
   399  	kvObjValue := kvObject.Value()
   400  
   401  	if kvObjValue == nil {
   402  		return types.BadRequestErrorf("invalid KV Object with a nil Value for key %s", Key(kvObject.Key()...))
   403  	}
   404  
   405  	if kvObject.Skip() {
   406  		goto add_cache
   407  	}
   408  
   409  	if kvObject.Exists() {
   410  		previous = &store.KVPair{Key: Key(kvObject.Key()...), LastIndex: kvObject.Index()}
   411  	} else {
   412  		previous = nil
   413  	}
   414  
   415  	_, pair, err = ds.store.AtomicPut(Key(kvObject.Key()...), kvObjValue, previous, nil)
   416  	if err != nil {
   417  		if err == store.ErrKeyExists {
   418  			return ErrKeyModified
   419  		}
   420  		return err
   421  	}
   422  
   423  	kvObject.SetIndex(pair.LastIndex)
   424  
   425  add_cache:
   426  	if ds.cache != nil {
   427  		// If persistent store is skipped, sequencing needs to
   428  		// happen in cache.
   429  		return ds.cache.add(kvObject, kvObject.Skip())
   430  	}
   431  
   432  	return nil
   433  }
   434  
   435  // PutObject adds a new Record based on an object into the datastore
   436  func (ds *datastore) PutObject(kvObject KVObject) error {
   437  	if ds.sequential {
   438  		ds.Lock()
   439  		defer ds.Unlock()
   440  	}
   441  
   442  	if kvObject == nil {
   443  		return types.BadRequestErrorf("invalid KV Object : nil")
   444  	}
   445  
   446  	if kvObject.Skip() {
   447  		goto add_cache
   448  	}
   449  
   450  	if err := ds.putObjectWithKey(kvObject, kvObject.Key()...); err != nil {
   451  		return err
   452  	}
   453  
   454  add_cache:
   455  	if ds.cache != nil {
   456  		// If persistent store is skipped, sequencing needs to
   457  		// happen in cache.
   458  		return ds.cache.add(kvObject, kvObject.Skip())
   459  	}
   460  
   461  	return nil
   462  }
   463  
   464  func (ds *datastore) putObjectWithKey(kvObject KVObject, key ...string) error {
   465  	kvObjValue := kvObject.Value()
   466  
   467  	if kvObjValue == nil {
   468  		return types.BadRequestErrorf("invalid KV Object with a nil Value for key %s", Key(kvObject.Key()...))
   469  	}
   470  	return ds.store.Put(Key(key...), kvObjValue, nil)
   471  }
   472  
   473  // GetObject returns a record matching the key
   474  func (ds *datastore) GetObject(key string, o KVObject) error {
   475  	if ds.sequential {
   476  		ds.Lock()
   477  		defer ds.Unlock()
   478  	}
   479  
   480  	if ds.cache != nil {
   481  		return ds.cache.get(key, o)
   482  	}
   483  
   484  	kvPair, err := ds.store.Get(key)
   485  	if err != nil {
   486  		return err
   487  	}
   488  
   489  	if err := o.SetValue(kvPair.Value); err != nil {
   490  		return err
   491  	}
   492  
   493  	// Make sure the object has a correct view of the DB index in
   494  	// case we need to modify it and update the DB.
   495  	o.SetIndex(kvPair.LastIndex)
   496  	return nil
   497  }
   498  
   499  func (ds *datastore) ensureParent(parent string) error {
   500  	exists, err := ds.store.Exists(parent)
   501  	if err != nil {
   502  		return err
   503  	}
   504  	if exists {
   505  		return nil
   506  	}
   507  	return ds.store.Put(parent, []byte{}, &store.WriteOptions{IsDir: true})
   508  }
   509  
   510  func (ds *datastore) List(key string, kvObject KVObject) ([]KVObject, error) {
   511  	if ds.sequential {
   512  		ds.Lock()
   513  		defer ds.Unlock()
   514  	}
   515  
   516  	if ds.cache != nil {
   517  		return ds.cache.list(kvObject)
   518  	}
   519  
   520  	var kvol []KVObject
   521  	cb := func(key string, val KVObject) {
   522  		kvol = append(kvol, val)
   523  	}
   524  	err := ds.iterateKVPairsFromStore(key, kvObject, cb)
   525  	if err != nil {
   526  		return nil, err
   527  	}
   528  	return kvol, nil
   529  }
   530  
   531  func (ds *datastore) iterateKVPairsFromStore(key string, kvObject KVObject, callback func(string, KVObject)) error {
   532  	// Bail out right away if the kvObject does not implement KVConstructor
   533  	ctor, ok := kvObject.(KVConstructor)
   534  	if !ok {
   535  		return fmt.Errorf("error listing objects, object does not implement KVConstructor interface")
   536  	}
   537  
   538  	// Make sure the parent key exists
   539  	if err := ds.ensureParent(key); err != nil {
   540  		return err
   541  	}
   542  
   543  	kvList, err := ds.store.List(key)
   544  	if err != nil {
   545  		return err
   546  	}
   547  
   548  	for _, kvPair := range kvList {
   549  		if len(kvPair.Value) == 0 {
   550  			continue
   551  		}
   552  
   553  		dstO := ctor.New()
   554  		if err := dstO.SetValue(kvPair.Value); err != nil {
   555  			return err
   556  		}
   557  
   558  		// Make sure the object has a correct view of the DB index in
   559  		// case we need to modify it and update the DB.
   560  		dstO.SetIndex(kvPair.LastIndex)
   561  		callback(kvPair.Key, dstO)
   562  	}
   563  
   564  	return nil
   565  }
   566  
   567  func (ds *datastore) Map(key string, kvObject KVObject) (map[string]KVObject, error) {
   568  	if ds.sequential {
   569  		ds.Lock()
   570  		defer ds.Unlock()
   571  	}
   572  
   573  	kvol := make(map[string]KVObject)
   574  	cb := func(key string, val KVObject) {
   575  		// Trim the leading & trailing "/" to make it consistent across all stores
   576  		kvol[strings.Trim(key, "/")] = val
   577  	}
   578  	err := ds.iterateKVPairsFromStore(key, kvObject, cb)
   579  	if err != nil {
   580  		return nil, err
   581  	}
   582  	return kvol, nil
   583  }
   584  
   585  // DeleteObject unconditionally deletes a record from the store
   586  func (ds *datastore) DeleteObject(kvObject KVObject) error {
   587  	if ds.sequential {
   588  		ds.Lock()
   589  		defer ds.Unlock()
   590  	}
   591  
   592  	// cleanup the cache first
   593  	if ds.cache != nil {
   594  		// If persistent store is skipped, sequencing needs to
   595  		// happen in cache.
   596  		ds.cache.del(kvObject, kvObject.Skip())
   597  	}
   598  
   599  	if kvObject.Skip() {
   600  		return nil
   601  	}
   602  
   603  	return ds.store.Delete(Key(kvObject.Key()...))
   604  }
   605  
   606  // DeleteObjectAtomic performs atomic delete on a record
   607  func (ds *datastore) DeleteObjectAtomic(kvObject KVObject) error {
   608  	if ds.sequential {
   609  		ds.Lock()
   610  		defer ds.Unlock()
   611  	}
   612  
   613  	if kvObject == nil {
   614  		return types.BadRequestErrorf("invalid KV Object : nil")
   615  	}
   616  
   617  	previous := &store.KVPair{Key: Key(kvObject.Key()...), LastIndex: kvObject.Index()}
   618  
   619  	if kvObject.Skip() {
   620  		goto del_cache
   621  	}
   622  
   623  	if _, err := ds.store.AtomicDelete(Key(kvObject.Key()...), previous); err != nil {
   624  		if err == store.ErrKeyExists {
   625  			return ErrKeyModified
   626  		}
   627  		return err
   628  	}
   629  
   630  del_cache:
   631  	// cleanup the cache only if AtomicDelete went through successfully
   632  	if ds.cache != nil {
   633  		// If persistent store is skipped, sequencing needs to
   634  		// happen in cache.
   635  		return ds.cache.del(kvObject, kvObject.Skip())
   636  	}
   637  
   638  	return nil
   639  }
   640  
   641  // DeleteTree unconditionally deletes a record from the store
   642  func (ds *datastore) DeleteTree(kvObject KVObject) error {
   643  	if ds.sequential {
   644  		ds.Lock()
   645  		defer ds.Unlock()
   646  	}
   647  
   648  	// cleanup the cache first
   649  	if ds.cache != nil {
   650  		// If persistent store is skipped, sequencing needs to
   651  		// happen in cache.
   652  		ds.cache.del(kvObject, kvObject.Skip())
   653  	}
   654  
   655  	if kvObject.Skip() {
   656  		return nil
   657  	}
   658  
   659  	return ds.store.DeleteTree(Key(kvObject.KeyPrefix()...))
   660  }