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 }