2018-06-11 20:33:18 +00:00
|
|
|
package state
|
2017-05-01 23:18:03 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2018-08-08 00:46:37 +00:00
|
|
|
"path/filepath"
|
2017-05-01 23:18:03 +00:00
|
|
|
|
2018-10-04 23:22:01 +00:00
|
|
|
trstate "github.com/hashicorp/nomad/client/allocrunner/taskrunner/state"
|
2018-11-01 01:00:30 +00:00
|
|
|
dmstate "github.com/hashicorp/nomad/client/devicemanager/state"
|
2018-11-28 03:42:22 +00:00
|
|
|
driverstate "github.com/hashicorp/nomad/client/pluginmanager/drivermanager/state"
|
2018-08-16 18:14:52 +00:00
|
|
|
"github.com/hashicorp/nomad/helper/boltdd"
|
2017-05-01 23:18:03 +00:00
|
|
|
"github.com/hashicorp/nomad/nomad/structs"
|
|
|
|
)
|
|
|
|
|
|
|
|
/*
|
2018-09-28 17:09:01 +00:00
|
|
|
The client has a boltDB backed state store. The schema as of 0.9 looks as follows:
|
2017-05-01 23:18:03 +00:00
|
|
|
|
|
|
|
allocations/ (bucket)
|
|
|
|
|--> <alloc-id>/ (bucket)
|
2018-08-08 00:46:37 +00:00
|
|
|
|--> alloc -> *structs.Allocation
|
2017-05-01 23:18:03 +00:00
|
|
|
|--> alloc_runner persisted objects (k/v)
|
|
|
|
|--> <task-name>/ (bucket)
|
|
|
|
|--> task_runner persisted objects (k/v)
|
2018-09-28 17:09:01 +00:00
|
|
|
|
|
|
|
devicemanager/
|
2018-11-01 01:00:30 +00:00
|
|
|
|--> plugin-state -> *dmstate.PluginState
|
2018-11-28 03:42:22 +00:00
|
|
|
|
|
|
|
drivermanager/
|
|
|
|
|--> plugin-state -> *driverstate.PluginState
|
2017-05-01 23:18:03 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
var (
|
2018-10-16 22:17:36 +00:00
|
|
|
// allocationsBucketName is the bucket name containing all allocation related
|
2017-05-01 23:18:03 +00:00
|
|
|
// data
|
2018-10-16 22:17:36 +00:00
|
|
|
allocationsBucketName = []byte("allocations")
|
2018-08-08 00:46:37 +00:00
|
|
|
|
|
|
|
// allocKey is the key serialized Allocations are stored under
|
|
|
|
allocKey = []byte("alloc")
|
|
|
|
|
|
|
|
// taskRunnerStateAllKey holds all the task runners state. At the moment
|
|
|
|
// there is no need to split it
|
|
|
|
//XXX Old key - going to need to migrate
|
|
|
|
//taskRunnerStateAllKey = []byte("simple-all")
|
|
|
|
|
|
|
|
// allocations -> $allocid -> $taskname -> the keys below
|
|
|
|
taskLocalStateKey = []byte("local_state")
|
|
|
|
taskStateKey = []byte("task_state")
|
2018-09-28 17:09:01 +00:00
|
|
|
|
|
|
|
// devManagerBucket is the bucket name containing all device manager related
|
|
|
|
// data
|
|
|
|
devManagerBucket = []byte("devicemanager")
|
|
|
|
|
2018-11-28 03:42:22 +00:00
|
|
|
// driverManagerBucket is the bucket name container all driver manager
|
|
|
|
// related data
|
|
|
|
driverManagerBucket = []byte("drivermanager")
|
|
|
|
|
|
|
|
// managerPluginStateKey is the key by which plugin manager plugin state is
|
|
|
|
// stored at
|
|
|
|
managerPluginStateKey = []byte("plugin_state")
|
2017-05-01 23:18:03 +00:00
|
|
|
)
|
|
|
|
|
2018-08-09 00:06:56 +00:00
|
|
|
// NewStateDBFunc creates a StateDB given a state directory.
|
|
|
|
type NewStateDBFunc func(stateDir string) (StateDB, error)
|
2018-08-08 00:46:37 +00:00
|
|
|
|
2018-08-09 00:06:56 +00:00
|
|
|
// GetStateDBFactory returns a func for creating a StateDB
|
|
|
|
func GetStateDBFactory(devMode bool) NewStateDBFunc {
|
|
|
|
// Return a noop state db implementation when in debug mode
|
|
|
|
if devMode {
|
|
|
|
return func(string) (StateDB, error) {
|
2018-09-27 00:29:08 +00:00
|
|
|
return NoopDB{}, nil
|
2018-08-08 00:46:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-09 00:06:56 +00:00
|
|
|
return NewBoltStateDB
|
2018-08-08 00:46:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// BoltStateDB persists and restores Nomad client state in a boltdb. All
|
2018-08-22 17:18:49 +00:00
|
|
|
// methods are safe for concurrent access.
|
2018-08-08 00:46:37 +00:00
|
|
|
type BoltStateDB struct {
|
2018-08-16 18:14:52 +00:00
|
|
|
db *boltdd.DB
|
2018-08-08 00:46:37 +00:00
|
|
|
}
|
|
|
|
|
2018-08-22 17:18:49 +00:00
|
|
|
// NewBoltStateDB creates or opens an existing boltdb state file or returns an
|
|
|
|
// error.
|
2018-08-09 00:06:56 +00:00
|
|
|
func NewBoltStateDB(stateDir string) (StateDB, error) {
|
2018-08-08 00:46:37 +00:00
|
|
|
// Create or open the boltdb state database
|
2018-08-16 18:14:52 +00:00
|
|
|
db, err := boltdd.Open(filepath.Join(stateDir, "state.db"), 0600, nil)
|
2018-08-08 00:46:37 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to create state database: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
sdb := &BoltStateDB{
|
2018-08-16 18:14:52 +00:00
|
|
|
db: db,
|
2018-08-08 00:46:37 +00:00
|
|
|
}
|
|
|
|
return sdb, nil
|
|
|
|
}
|
|
|
|
|
2018-10-16 22:17:36 +00:00
|
|
|
func (s *BoltStateDB) Name() string {
|
|
|
|
return "boltdb"
|
|
|
|
}
|
|
|
|
|
2018-08-08 00:46:37 +00:00
|
|
|
// GetAllAllocations gets all allocations persisted by this client and returns
|
|
|
|
// a map of alloc ids to errors for any allocations that could not be restored.
|
|
|
|
//
|
|
|
|
// If a fatal error was encountered it will be returned and the other two
|
|
|
|
// values will be nil.
|
|
|
|
func (s *BoltStateDB) GetAllAllocations() ([]*structs.Allocation, map[string]error, error) {
|
|
|
|
var allocs []*structs.Allocation
|
|
|
|
var errs map[string]error
|
2018-08-16 18:14:52 +00:00
|
|
|
err := s.db.View(func(tx *boltdd.Tx) error {
|
2018-08-09 00:06:56 +00:00
|
|
|
allocs, errs = s.getAllAllocations(tx)
|
2018-08-08 00:46:37 +00:00
|
|
|
return nil
|
|
|
|
})
|
|
|
|
|
|
|
|
// db.View itself may return an error, so still check
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return allocs, errs, nil
|
|
|
|
}
|
|
|
|
|
2018-08-09 00:06:56 +00:00
|
|
|
// allocEntry wraps values in the Allocations buckets
|
|
|
|
type allocEntry struct {
|
|
|
|
Alloc *structs.Allocation
|
|
|
|
}
|
|
|
|
|
2018-08-16 18:14:52 +00:00
|
|
|
func (s *BoltStateDB) getAllAllocations(tx *boltdd.Tx) ([]*structs.Allocation, map[string]error) {
|
2018-10-16 22:17:36 +00:00
|
|
|
allocs := []*structs.Allocation{}
|
|
|
|
errs := map[string]error{}
|
|
|
|
|
|
|
|
allocationsBkt := tx.Bucket(allocationsBucketName)
|
2018-08-09 00:06:56 +00:00
|
|
|
if allocationsBkt == nil {
|
|
|
|
// No allocs
|
2018-10-16 22:17:36 +00:00
|
|
|
return allocs, errs
|
2018-08-09 00:06:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Create a cursor for iteration.
|
2018-08-16 18:14:52 +00:00
|
|
|
c := allocationsBkt.BoltBucket().Cursor()
|
2018-08-09 00:06:56 +00:00
|
|
|
|
|
|
|
// Iterate over all the allocation buckets
|
|
|
|
for k, _ := c.First(); k != nil; k, _ = c.Next() {
|
|
|
|
allocID := string(k)
|
|
|
|
allocBkt := allocationsBkt.Bucket(k)
|
|
|
|
if allocBkt == nil {
|
|
|
|
errs[allocID] = fmt.Errorf("missing alloc bucket")
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2018-08-22 17:18:49 +00:00
|
|
|
var ae allocEntry
|
|
|
|
if err := allocBkt.Get(allocKey, &ae); err != nil {
|
|
|
|
errs[allocID] = fmt.Errorf("failed to decode alloc: %v", err)
|
2018-08-09 00:06:56 +00:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2018-08-22 17:18:49 +00:00
|
|
|
allocs = append(allocs, ae.Alloc)
|
2018-08-09 00:06:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return allocs, errs
|
|
|
|
}
|
|
|
|
|
2018-08-08 00:46:37 +00:00
|
|
|
// PutAllocation stores an allocation or returns an error.
|
|
|
|
func (s *BoltStateDB) PutAllocation(alloc *structs.Allocation) error {
|
2018-08-16 18:14:52 +00:00
|
|
|
return s.db.Update(func(tx *boltdd.Tx) error {
|
2018-08-08 00:46:37 +00:00
|
|
|
// Retrieve the root allocations bucket
|
2018-10-16 22:17:36 +00:00
|
|
|
allocsBkt, err := tx.CreateBucketIfNotExists(allocationsBucketName)
|
2018-08-08 00:46:37 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Retrieve the specific allocations bucket
|
|
|
|
key := []byte(alloc.ID)
|
|
|
|
allocBkt, err := allocsBkt.CreateBucketIfNotExists(key)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
allocState := allocEntry{
|
|
|
|
Alloc: alloc,
|
|
|
|
}
|
2018-08-16 18:14:52 +00:00
|
|
|
return allocBkt.Put(allocKey, &allocState)
|
2018-08-08 00:46:37 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2018-10-16 22:17:36 +00:00
|
|
|
// GetTaskRunnerState returns the LocalState and TaskState for a
|
|
|
|
// TaskRunner. LocalState or TaskState will be nil if they do not exist.
|
|
|
|
//
|
|
|
|
// If an error is encountered both LocalState and TaskState will be nil.
|
2018-08-08 00:46:37 +00:00
|
|
|
func (s *BoltStateDB) GetTaskRunnerState(allocID, taskName string) (*trstate.LocalState, *structs.TaskState, error) {
|
2018-10-16 22:17:36 +00:00
|
|
|
var ls *trstate.LocalState
|
|
|
|
var ts *structs.TaskState
|
2018-08-08 00:46:37 +00:00
|
|
|
|
2018-08-16 18:14:52 +00:00
|
|
|
err := s.db.View(func(tx *boltdd.Tx) error {
|
2018-10-16 22:17:36 +00:00
|
|
|
allAllocsBkt := tx.Bucket(allocationsBucketName)
|
|
|
|
if allAllocsBkt == nil {
|
|
|
|
// No state, return
|
|
|
|
return nil
|
2018-08-08 00:46:37 +00:00
|
|
|
}
|
|
|
|
|
2018-10-16 22:17:36 +00:00
|
|
|
allocBkt := allAllocsBkt.Bucket([]byte(allocID))
|
|
|
|
if allocBkt == nil {
|
|
|
|
// No state for alloc, return
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
taskBkt := allocBkt.Bucket([]byte(taskName))
|
|
|
|
if taskBkt == nil {
|
|
|
|
// No state for task, return
|
|
|
|
return nil
|
2018-08-08 00:46:37 +00:00
|
|
|
}
|
|
|
|
|
2018-10-16 22:17:36 +00:00
|
|
|
// Restore Local State if it exists
|
|
|
|
ls = &trstate.LocalState{}
|
|
|
|
if err := taskBkt.Get(taskLocalStateKey, ls); err != nil {
|
|
|
|
if !boltdd.IsErrNotFound(err) {
|
|
|
|
return fmt.Errorf("failed to read local task runner state: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Key not found, reset ls to nil
|
|
|
|
ls = nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Restore Task State if it exists
|
|
|
|
ts = &structs.TaskState{}
|
|
|
|
if err := taskBkt.Get(taskStateKey, ts); err != nil {
|
|
|
|
if !boltdd.IsErrNotFound(err) {
|
|
|
|
return fmt.Errorf("failed to read task state: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Key not found, reset ts to nil
|
|
|
|
ts = nil
|
2018-08-08 00:46:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
|
2018-10-16 22:17:36 +00:00
|
|
|
return ls, ts, nil
|
2018-08-08 00:46:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// PutTaskRunnerLocalState stores TaskRunner's LocalState or returns an error.
|
2018-10-16 22:17:36 +00:00
|
|
|
func (s *BoltStateDB) PutTaskRunnerLocalState(allocID, taskName string, val *trstate.LocalState) error {
|
2018-08-16 18:14:52 +00:00
|
|
|
return s.db.Update(func(tx *boltdd.Tx) error {
|
2018-08-08 00:46:37 +00:00
|
|
|
taskBkt, err := getTaskBucket(tx, allocID, taskName)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to retrieve allocation bucket: %v", err)
|
|
|
|
}
|
|
|
|
|
2018-08-16 18:14:52 +00:00
|
|
|
if err := taskBkt.Put(taskLocalStateKey, val); err != nil {
|
2018-08-08 00:46:37 +00:00
|
|
|
return fmt.Errorf("failed to write task_runner state: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// PutTaskState stores a task's state or returns an error.
|
|
|
|
func (s *BoltStateDB) PutTaskState(allocID, taskName string, state *structs.TaskState) error {
|
2018-08-16 18:14:52 +00:00
|
|
|
return s.db.Update(func(tx *boltdd.Tx) error {
|
2018-08-08 00:46:37 +00:00
|
|
|
taskBkt, err := getTaskBucket(tx, allocID, taskName)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to retrieve allocation bucket: %v", err)
|
|
|
|
}
|
|
|
|
|
2018-08-16 18:14:52 +00:00
|
|
|
return taskBkt.Put(taskStateKey, state)
|
2018-08-15 21:03:18 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// DeleteTaskBucket is used to delete a task bucket if it exists.
|
|
|
|
func (s *BoltStateDB) DeleteTaskBucket(allocID, taskName string) error {
|
2018-08-16 18:14:52 +00:00
|
|
|
return s.db.Update(func(tx *boltdd.Tx) error {
|
2018-08-15 21:03:18 +00:00
|
|
|
// Retrieve the root allocations bucket
|
2018-10-16 22:17:36 +00:00
|
|
|
allocations := tx.Bucket(allocationsBucketName)
|
2018-08-15 21:03:18 +00:00
|
|
|
if allocations == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Retrieve the specific allocations bucket
|
|
|
|
alloc := allocations.Bucket([]byte(allocID))
|
|
|
|
if alloc == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if the bucket exists
|
|
|
|
key := []byte(taskName)
|
2018-08-16 18:14:52 +00:00
|
|
|
return alloc.DeleteBucket(key)
|
2018-08-15 21:03:18 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// DeleteAllocationBucket is used to delete an allocation bucket if it exists.
|
|
|
|
func (s *BoltStateDB) DeleteAllocationBucket(allocID string) error {
|
2018-08-16 18:14:52 +00:00
|
|
|
return s.db.Update(func(tx *boltdd.Tx) error {
|
2018-08-15 21:03:18 +00:00
|
|
|
// Retrieve the root allocations bucket
|
2018-10-16 22:17:36 +00:00
|
|
|
allocations := tx.Bucket(allocationsBucketName)
|
2018-08-15 21:03:18 +00:00
|
|
|
if allocations == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
key := []byte(allocID)
|
2018-08-16 18:14:52 +00:00
|
|
|
return allocations.DeleteBucket(key)
|
2018-08-08 00:46:37 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// Close releases all database resources and unlocks the database file on disk.
|
|
|
|
// All transactions must be closed before closing the database.
|
|
|
|
func (s *BoltStateDB) Close() error {
|
|
|
|
return s.db.Close()
|
|
|
|
}
|
|
|
|
|
|
|
|
// getAllocationBucket returns the bucket used to persist state about a
|
2017-05-01 23:18:03 +00:00
|
|
|
// particular allocation. If the root allocation bucket or the specific
|
2017-05-02 20:31:56 +00:00
|
|
|
// allocation bucket doesn't exist, it will be created as long as the
|
|
|
|
// transaction is writable.
|
2018-08-16 18:14:52 +00:00
|
|
|
func getAllocationBucket(tx *boltdd.Tx, allocID string) (*boltdd.Bucket, error) {
|
2017-05-02 20:31:56 +00:00
|
|
|
var err error
|
|
|
|
w := tx.Writable()
|
2017-05-01 23:18:03 +00:00
|
|
|
|
|
|
|
// Retrieve the root allocations bucket
|
2018-10-16 22:17:36 +00:00
|
|
|
allocations := tx.Bucket(allocationsBucketName)
|
2017-05-02 20:31:56 +00:00
|
|
|
if allocations == nil {
|
|
|
|
if !w {
|
|
|
|
return nil, fmt.Errorf("Allocations bucket doesn't exist and transaction is not writable")
|
|
|
|
}
|
|
|
|
|
2018-10-16 22:17:36 +00:00
|
|
|
allocations, err = tx.CreateBucketIfNotExists(allocationsBucketName)
|
2017-05-02 20:31:56 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2017-05-01 23:18:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Retrieve the specific allocations bucket
|
2017-05-02 20:31:56 +00:00
|
|
|
key := []byte(allocID)
|
|
|
|
alloc := allocations.Bucket(key)
|
|
|
|
if alloc == nil {
|
|
|
|
if !w {
|
|
|
|
return nil, fmt.Errorf("Allocation bucket doesn't exist and transaction is not writable")
|
|
|
|
}
|
|
|
|
|
|
|
|
alloc, err = allocations.CreateBucket(key)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2017-05-01 23:18:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return alloc, nil
|
|
|
|
}
|
|
|
|
|
2018-08-08 00:46:37 +00:00
|
|
|
// getTaskBucket returns the bucket used to persist state about a
|
2017-05-01 23:18:03 +00:00
|
|
|
// particular task. If the root allocation bucket, the specific
|
2017-05-02 20:31:56 +00:00
|
|
|
// allocation or task bucket doesn't exist, they will be created as long as the
|
|
|
|
// transaction is writable.
|
2018-08-16 18:14:52 +00:00
|
|
|
func getTaskBucket(tx *boltdd.Tx, allocID, taskName string) (*boltdd.Bucket, error) {
|
2018-08-08 00:46:37 +00:00
|
|
|
alloc, err := getAllocationBucket(tx, allocID)
|
2017-05-02 20:31:56 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Retrieve the specific task bucket
|
|
|
|
w := tx.Writable()
|
|
|
|
key := []byte(taskName)
|
|
|
|
task := alloc.Bucket(key)
|
|
|
|
if task == nil {
|
|
|
|
if !w {
|
|
|
|
return nil, fmt.Errorf("Task bucket doesn't exist and transaction is not writable")
|
|
|
|
}
|
|
|
|
|
|
|
|
task, err = alloc.CreateBucket(key)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return task, nil
|
|
|
|
}
|
2018-09-28 17:09:01 +00:00
|
|
|
|
|
|
|
// PutDevicePluginState stores the device manager's plugin state or returns an
|
|
|
|
// error.
|
2018-11-01 01:00:30 +00:00
|
|
|
func (s *BoltStateDB) PutDevicePluginState(ps *dmstate.PluginState) error {
|
2018-09-28 17:09:01 +00:00
|
|
|
return s.db.Update(func(tx *boltdd.Tx) error {
|
|
|
|
// Retrieve the root device manager bucket
|
|
|
|
devBkt, err := tx.CreateBucketIfNotExists(devManagerBucket)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2018-11-28 03:42:22 +00:00
|
|
|
return devBkt.Put(managerPluginStateKey, ps)
|
2018-09-28 17:09:01 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetDevicePluginState stores the device manager's plugin state or returns an
|
|
|
|
// error.
|
2018-11-01 01:00:30 +00:00
|
|
|
func (s *BoltStateDB) GetDevicePluginState() (*dmstate.PluginState, error) {
|
|
|
|
var ps *dmstate.PluginState
|
2018-09-28 17:09:01 +00:00
|
|
|
|
|
|
|
err := s.db.View(func(tx *boltdd.Tx) error {
|
|
|
|
devBkt := tx.Bucket(devManagerBucket)
|
|
|
|
if devBkt == nil {
|
|
|
|
// No state, return
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Restore Plugin State if it exists
|
2018-11-01 01:00:30 +00:00
|
|
|
ps = &dmstate.PluginState{}
|
2018-11-28 03:42:22 +00:00
|
|
|
if err := devBkt.Get(managerPluginStateKey, ps); err != nil {
|
2018-09-28 17:09:01 +00:00
|
|
|
if !boltdd.IsErrNotFound(err) {
|
|
|
|
return fmt.Errorf("failed to read device manager plugin state: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Key not found, reset ps to nil
|
|
|
|
ps = nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return ps, nil
|
|
|
|
}
|
2018-11-28 03:42:22 +00:00
|
|
|
|
|
|
|
// PutDriverPluginState stores the driver manager's plugin state or returns an
|
|
|
|
// error.
|
|
|
|
func (s *BoltStateDB) PutDriverPluginState(ps *driverstate.PluginState) error {
|
|
|
|
return s.db.Update(func(tx *boltdd.Tx) error {
|
|
|
|
// Retrieve the root driver manager bucket
|
|
|
|
driverBkt, err := tx.CreateBucketIfNotExists(driverManagerBucket)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return driverBkt.Put(managerPluginStateKey, ps)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetDriverPluginState stores the driver manager's plugin state or returns an
|
|
|
|
// error.
|
|
|
|
func (s *BoltStateDB) GetDriverPluginState() (*driverstate.PluginState, error) {
|
|
|
|
var ps *driverstate.PluginState
|
|
|
|
|
|
|
|
err := s.db.View(func(tx *boltdd.Tx) error {
|
|
|
|
driverBkt := tx.Bucket(driverManagerBucket)
|
|
|
|
if driverBkt == nil {
|
|
|
|
// No state, return
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Restore Plugin State if it exists
|
|
|
|
ps = &driverstate.PluginState{}
|
|
|
|
if err := driverBkt.Get(managerPluginStateKey, ps); err != nil {
|
|
|
|
if !boltdd.IsErrNotFound(err) {
|
|
|
|
return fmt.Errorf("failed to read driver manager plugin state: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Key not found, reset ps to nil
|
|
|
|
ps = nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return ps, nil
|
|
|
|
}
|