github.com/rawahars/moby@v24.0.4+incompatible/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 defaultRootChain = []string{"docker", "network", "v1.0"}
   133  var rootChain = defaultRootChain
   134  
   135  // DefaultScope returns a default scope config for clients to use.
   136  func DefaultScope(dataDir string) ScopeCfg {
   137  	var dbpath string
   138  	if dataDir == "" {
   139  		dbpath = defaultPrefix + "/local-kv.db"
   140  	} else {
   141  		dbpath = dataDir + "/network/files/local-kv.db"
   142  	}
   143  
   144  	return ScopeCfg{
   145  		Client: ScopeClientCfg{
   146  			Provider: string(store.BOLTDB),
   147  			Address:  dbpath,
   148  			Config: &store.Config{
   149  				Bucket:            "libnetwork",
   150  				ConnectionTimeout: time.Minute,
   151  			},
   152  		},
   153  	}
   154  }
   155  
   156  // IsValid checks if the scope config has valid configuration.
   157  func (cfg *ScopeCfg) IsValid() bool {
   158  	if cfg == nil ||
   159  		strings.TrimSpace(cfg.Client.Provider) == "" ||
   160  		strings.TrimSpace(cfg.Client.Address) == "" {
   161  		return false
   162  	}
   163  
   164  	return true
   165  }
   166  
   167  // Key provides convenient method to create a Key
   168  func Key(key ...string) string {
   169  	keychain := append(rootChain, key...)
   170  	str := strings.Join(keychain, "/")
   171  	return str + "/"
   172  }
   173  
   174  // ParseKey provides convenient method to unpack the key to complement the Key function
   175  func ParseKey(key string) ([]string, error) {
   176  	chain := strings.Split(strings.Trim(key, "/"), "/")
   177  
   178  	// The key must at least be equal to the rootChain in order to be considered as valid
   179  	if len(chain) <= len(rootChain) || !reflect.DeepEqual(chain[0:len(rootChain)], rootChain) {
   180  		return nil, types.BadRequestErrorf("invalid Key : %s", key)
   181  	}
   182  	return chain[len(rootChain):], nil
   183  }
   184  
   185  // newClient used to connect to KV Store
   186  func newClient(kv string, addr string, config *store.Config) (DataStore, error) {
   187  	if config == nil {
   188  		config = &store.Config{}
   189  	}
   190  
   191  	var addrs []string
   192  
   193  	if kv == string(store.BOLTDB) {
   194  		// Parse file path
   195  		addrs = strings.Split(addr, ",")
   196  	} else {
   197  		// Parse URI
   198  		parts := strings.SplitN(addr, "/", 2)
   199  		addrs = strings.Split(parts[0], ",")
   200  
   201  		// Add the custom prefix to the root chain
   202  		if len(parts) == 2 {
   203  			rootChain = append([]string{parts[1]}, defaultRootChain...)
   204  		}
   205  	}
   206  
   207  	s, err := libkv.NewStore(store.Backend(kv), addrs, config)
   208  	if err != nil {
   209  		return nil, err
   210  	}
   211  
   212  	ds := &datastore{scope: LocalScope, store: s, active: true, watchCh: make(chan struct{}), sequential: true}
   213  	ds.cache = newCache(ds)
   214  
   215  	return ds, nil
   216  }
   217  
   218  // NewDataStore creates a new instance of LibKV data store
   219  func NewDataStore(cfg ScopeCfg) (DataStore, error) {
   220  	if cfg.Client.Provider == "" || cfg.Client.Address == "" {
   221  		cfg = DefaultScope("")
   222  	}
   223  
   224  	return newClient(cfg.Client.Provider, cfg.Client.Address, cfg.Client.Config)
   225  }
   226  
   227  // NewDataStoreFromConfig creates a new instance of LibKV data store starting from the datastore config data
   228  func NewDataStoreFromConfig(dsc discoverapi.DatastoreConfigData) (DataStore, error) {
   229  	var (
   230  		ok    bool
   231  		sCfgP *store.Config
   232  	)
   233  
   234  	sCfgP, ok = dsc.Config.(*store.Config)
   235  	if !ok && dsc.Config != nil {
   236  		return nil, fmt.Errorf("cannot parse store configuration: %v", dsc.Config)
   237  	}
   238  
   239  	scopeCfg := ScopeCfg{
   240  		Client: ScopeClientCfg{
   241  			Address:  dsc.Address,
   242  			Provider: dsc.Provider,
   243  			Config:   sCfgP,
   244  		},
   245  	}
   246  
   247  	ds, err := NewDataStore(scopeCfg)
   248  	if err != nil {
   249  		return nil, fmt.Errorf("failed to construct datastore client from datastore configuration %v: %v", dsc, err)
   250  	}
   251  
   252  	return ds, err
   253  }
   254  
   255  func (ds *datastore) Close() {
   256  	ds.store.Close()
   257  }
   258  
   259  func (ds *datastore) Scope() string {
   260  	return ds.scope
   261  }
   262  
   263  func (ds *datastore) Active() bool {
   264  	return ds.active
   265  }
   266  
   267  func (ds *datastore) Watchable() bool {
   268  	return ds.scope != LocalScope
   269  }
   270  
   271  func (ds *datastore) Watch(kvObject KVObject, stopCh <-chan struct{}) (<-chan KVObject, error) {
   272  	sCh := make(chan struct{})
   273  
   274  	ctor, ok := kvObject.(KVConstructor)
   275  	if !ok {
   276  		return nil, fmt.Errorf("error watching object type %T, object does not implement KVConstructor interface", kvObject)
   277  	}
   278  
   279  	kvpCh, err := ds.store.Watch(Key(kvObject.Key()...), sCh)
   280  	if err != nil {
   281  		return nil, err
   282  	}
   283  
   284  	kvoCh := make(chan KVObject)
   285  
   286  	go func() {
   287  	retry_watch:
   288  		var err error
   289  
   290  		// Make sure to get a new instance of watch channel
   291  		ds.Lock()
   292  		watchCh := ds.watchCh
   293  		ds.Unlock()
   294  
   295  	loop:
   296  		for {
   297  			select {
   298  			case <-stopCh:
   299  				close(sCh)
   300  				return
   301  			case kvPair := <-kvpCh:
   302  				// If the backend KV store gets reset libkv's go routine
   303  				// for the watch can exit resulting in a nil value in
   304  				// channel.
   305  				if kvPair == nil {
   306  					ds.Lock()
   307  					ds.active = false
   308  					ds.Unlock()
   309  					break loop
   310  				}
   311  
   312  				dstO := ctor.New()
   313  
   314  				if err = dstO.SetValue(kvPair.Value); err != nil {
   315  					log.Printf("Could not unmarshal kvpair value = %s", string(kvPair.Value))
   316  					break
   317  				}
   318  
   319  				dstO.SetIndex(kvPair.LastIndex)
   320  				kvoCh <- dstO
   321  			}
   322  		}
   323  
   324  		// Wait on watch channel for a re-trigger when datastore becomes active
   325  		<-watchCh
   326  
   327  		kvpCh, err = ds.store.Watch(Key(kvObject.Key()...), sCh)
   328  		if err != nil {
   329  			log.Printf("Could not watch the key %s in store: %v", Key(kvObject.Key()...), err)
   330  		}
   331  
   332  		goto retry_watch
   333  	}()
   334  
   335  	return kvoCh, nil
   336  }
   337  
   338  func (ds *datastore) RestartWatch() {
   339  	ds.Lock()
   340  	defer ds.Unlock()
   341  
   342  	ds.active = true
   343  	watchCh := ds.watchCh
   344  	ds.watchCh = make(chan struct{})
   345  	close(watchCh)
   346  }
   347  
   348  func (ds *datastore) KVStore() store.Store {
   349  	return ds.store
   350  }
   351  
   352  // PutObjectAtomic adds a new Record based on an object into the datastore
   353  func (ds *datastore) PutObjectAtomic(kvObject KVObject) error {
   354  	var (
   355  		previous *store.KVPair
   356  		pair     *store.KVPair
   357  		err      error
   358  	)
   359  	if ds.sequential {
   360  		ds.Lock()
   361  		defer ds.Unlock()
   362  	}
   363  
   364  	if kvObject == nil {
   365  		return types.BadRequestErrorf("invalid KV Object : nil")
   366  	}
   367  
   368  	kvObjValue := kvObject.Value()
   369  
   370  	if kvObjValue == nil {
   371  		return types.BadRequestErrorf("invalid KV Object with a nil Value for key %s", Key(kvObject.Key()...))
   372  	}
   373  
   374  	if kvObject.Skip() {
   375  		goto add_cache
   376  	}
   377  
   378  	if kvObject.Exists() {
   379  		previous = &store.KVPair{Key: Key(kvObject.Key()...), LastIndex: kvObject.Index()}
   380  	} else {
   381  		previous = nil
   382  	}
   383  
   384  	_, pair, err = ds.store.AtomicPut(Key(kvObject.Key()...), kvObjValue, previous, nil)
   385  	if err != nil {
   386  		if err == store.ErrKeyExists {
   387  			return ErrKeyModified
   388  		}
   389  		return err
   390  	}
   391  
   392  	kvObject.SetIndex(pair.LastIndex)
   393  
   394  add_cache:
   395  	if ds.cache != nil {
   396  		// If persistent store is skipped, sequencing needs to
   397  		// happen in cache.
   398  		return ds.cache.add(kvObject, kvObject.Skip())
   399  	}
   400  
   401  	return nil
   402  }
   403  
   404  // PutObject adds a new Record based on an object into the datastore
   405  func (ds *datastore) PutObject(kvObject KVObject) error {
   406  	if ds.sequential {
   407  		ds.Lock()
   408  		defer ds.Unlock()
   409  	}
   410  
   411  	if kvObject == nil {
   412  		return types.BadRequestErrorf("invalid KV Object : nil")
   413  	}
   414  
   415  	if kvObject.Skip() {
   416  		goto add_cache
   417  	}
   418  
   419  	if err := ds.putObjectWithKey(kvObject, kvObject.Key()...); err != nil {
   420  		return err
   421  	}
   422  
   423  add_cache:
   424  	if ds.cache != nil {
   425  		// If persistent store is skipped, sequencing needs to
   426  		// happen in cache.
   427  		return ds.cache.add(kvObject, kvObject.Skip())
   428  	}
   429  
   430  	return nil
   431  }
   432  
   433  func (ds *datastore) putObjectWithKey(kvObject KVObject, key ...string) error {
   434  	kvObjValue := kvObject.Value()
   435  
   436  	if kvObjValue == nil {
   437  		return types.BadRequestErrorf("invalid KV Object with a nil Value for key %s", Key(kvObject.Key()...))
   438  	}
   439  	return ds.store.Put(Key(key...), kvObjValue, nil)
   440  }
   441  
   442  // GetObject returns a record matching the key
   443  func (ds *datastore) GetObject(key string, o KVObject) error {
   444  	if ds.sequential {
   445  		ds.Lock()
   446  		defer ds.Unlock()
   447  	}
   448  
   449  	if ds.cache != nil {
   450  		return ds.cache.get(key, o)
   451  	}
   452  
   453  	kvPair, err := ds.store.Get(key)
   454  	if err != nil {
   455  		return err
   456  	}
   457  
   458  	if err := o.SetValue(kvPair.Value); err != nil {
   459  		return err
   460  	}
   461  
   462  	// Make sure the object has a correct view of the DB index in
   463  	// case we need to modify it and update the DB.
   464  	o.SetIndex(kvPair.LastIndex)
   465  	return nil
   466  }
   467  
   468  func (ds *datastore) ensureParent(parent string) error {
   469  	exists, err := ds.store.Exists(parent)
   470  	if err != nil {
   471  		return err
   472  	}
   473  	if exists {
   474  		return nil
   475  	}
   476  	return ds.store.Put(parent, []byte{}, &store.WriteOptions{IsDir: true})
   477  }
   478  
   479  func (ds *datastore) List(key string, kvObject KVObject) ([]KVObject, error) {
   480  	if ds.sequential {
   481  		ds.Lock()
   482  		defer ds.Unlock()
   483  	}
   484  
   485  	if ds.cache != nil {
   486  		return ds.cache.list(kvObject)
   487  	}
   488  
   489  	var kvol []KVObject
   490  	cb := func(key string, val KVObject) {
   491  		kvol = append(kvol, val)
   492  	}
   493  	err := ds.iterateKVPairsFromStore(key, kvObject, cb)
   494  	if err != nil {
   495  		return nil, err
   496  	}
   497  	return kvol, nil
   498  }
   499  
   500  func (ds *datastore) iterateKVPairsFromStore(key string, kvObject KVObject, callback func(string, KVObject)) error {
   501  	// Bail out right away if the kvObject does not implement KVConstructor
   502  	ctor, ok := kvObject.(KVConstructor)
   503  	if !ok {
   504  		return fmt.Errorf("error listing objects, object does not implement KVConstructor interface")
   505  	}
   506  
   507  	// Make sure the parent key exists
   508  	if err := ds.ensureParent(key); err != nil {
   509  		return err
   510  	}
   511  
   512  	kvList, err := ds.store.List(key)
   513  	if err != nil {
   514  		return err
   515  	}
   516  
   517  	for _, kvPair := range kvList {
   518  		if len(kvPair.Value) == 0 {
   519  			continue
   520  		}
   521  
   522  		dstO := ctor.New()
   523  		if err := dstO.SetValue(kvPair.Value); err != nil {
   524  			return err
   525  		}
   526  
   527  		// Make sure the object has a correct view of the DB index in
   528  		// case we need to modify it and update the DB.
   529  		dstO.SetIndex(kvPair.LastIndex)
   530  		callback(kvPair.Key, dstO)
   531  	}
   532  
   533  	return nil
   534  }
   535  
   536  func (ds *datastore) Map(key string, kvObject KVObject) (map[string]KVObject, error) {
   537  	if ds.sequential {
   538  		ds.Lock()
   539  		defer ds.Unlock()
   540  	}
   541  
   542  	kvol := make(map[string]KVObject)
   543  	cb := func(key string, val KVObject) {
   544  		// Trim the leading & trailing "/" to make it consistent across all stores
   545  		kvol[strings.Trim(key, "/")] = val
   546  	}
   547  	err := ds.iterateKVPairsFromStore(key, kvObject, cb)
   548  	if err != nil {
   549  		return nil, err
   550  	}
   551  	return kvol, nil
   552  }
   553  
   554  // DeleteObject unconditionally deletes a record from the store
   555  func (ds *datastore) DeleteObject(kvObject KVObject) error {
   556  	if ds.sequential {
   557  		ds.Lock()
   558  		defer ds.Unlock()
   559  	}
   560  
   561  	// cleanup the cache first
   562  	if ds.cache != nil {
   563  		// If persistent store is skipped, sequencing needs to
   564  		// happen in cache.
   565  		ds.cache.del(kvObject, kvObject.Skip())
   566  	}
   567  
   568  	if kvObject.Skip() {
   569  		return nil
   570  	}
   571  
   572  	return ds.store.Delete(Key(kvObject.Key()...))
   573  }
   574  
   575  // DeleteObjectAtomic performs atomic delete on a record
   576  func (ds *datastore) DeleteObjectAtomic(kvObject KVObject) error {
   577  	if ds.sequential {
   578  		ds.Lock()
   579  		defer ds.Unlock()
   580  	}
   581  
   582  	if kvObject == nil {
   583  		return types.BadRequestErrorf("invalid KV Object : nil")
   584  	}
   585  
   586  	previous := &store.KVPair{Key: Key(kvObject.Key()...), LastIndex: kvObject.Index()}
   587  
   588  	if kvObject.Skip() {
   589  		goto del_cache
   590  	}
   591  
   592  	if _, err := ds.store.AtomicDelete(Key(kvObject.Key()...), previous); err != nil {
   593  		if err == store.ErrKeyExists {
   594  			return ErrKeyModified
   595  		}
   596  		return err
   597  	}
   598  
   599  del_cache:
   600  	// cleanup the cache only if AtomicDelete went through successfully
   601  	if ds.cache != nil {
   602  		// If persistent store is skipped, sequencing needs to
   603  		// happen in cache.
   604  		return ds.cache.del(kvObject, kvObject.Skip())
   605  	}
   606  
   607  	return nil
   608  }
   609  
   610  // DeleteTree unconditionally deletes a record from the store
   611  func (ds *datastore) DeleteTree(kvObject KVObject) error {
   612  	if ds.sequential {
   613  		ds.Lock()
   614  		defer ds.Unlock()
   615  	}
   616  
   617  	// cleanup the cache first
   618  	if ds.cache != nil {
   619  		// If persistent store is skipped, sequencing needs to
   620  		// happen in cache.
   621  		ds.cache.del(kvObject, kvObject.Skip())
   622  	}
   623  
   624  	if kvObject.Skip() {
   625  		return nil
   626  	}
   627  
   628  	return ds.store.DeleteTree(Key(kvObject.KeyPrefix()...))
   629  }