github.com/iaas-resource-provision/iaas-rpc@v1.0.7-0.20211021023331-ed21f798c408/internal/backend/remote-state/etcdv3/backend_state.go (about) 1 package etcd 2 3 import ( 4 "context" 5 "fmt" 6 "sort" 7 "strings" 8 9 etcdv3 "go.etcd.io/etcd/clientv3" 10 11 "github.com/iaas-resource-provision/iaas-rpc/internal/backend" 12 "github.com/iaas-resource-provision/iaas-rpc/internal/states" 13 "github.com/iaas-resource-provision/iaas-rpc/internal/states/remote" 14 "github.com/iaas-resource-provision/iaas-rpc/internal/states/statemgr" 15 ) 16 17 func (b *Backend) Workspaces() ([]string, error) { 18 res, err := b.client.Get(context.TODO(), b.prefix, etcdv3.WithPrefix(), etcdv3.WithKeysOnly()) 19 if err != nil { 20 return nil, err 21 } 22 23 result := make([]string, 1, len(res.Kvs)+1) 24 result[0] = backend.DefaultStateName 25 for _, kv := range res.Kvs { 26 result = append(result, strings.TrimPrefix(string(kv.Key), b.prefix)) 27 } 28 sort.Strings(result[1:]) 29 30 return result, nil 31 } 32 33 func (b *Backend) DeleteWorkspace(name string) error { 34 if name == backend.DefaultStateName || name == "" { 35 return fmt.Errorf("Can't delete default state.") 36 } 37 38 key := b.determineKey(name) 39 40 _, err := b.client.Delete(context.TODO(), key) 41 return err 42 } 43 44 func (b *Backend) StateMgr(name string) (statemgr.Full, error) { 45 var stateMgr statemgr.Full = &remote.State{ 46 Client: &RemoteClient{ 47 Client: b.client, 48 DoLock: b.lock, 49 Key: b.determineKey(name), 50 }, 51 } 52 53 if !b.lock { 54 stateMgr = &statemgr.LockDisabled{Inner: stateMgr} 55 } 56 57 lockInfo := statemgr.NewLockInfo() 58 lockInfo.Operation = "init" 59 lockUnlock := func(parent error) error { 60 return nil 61 } 62 63 if err := stateMgr.RefreshState(); err != nil { 64 err = lockUnlock(err) 65 return nil, err 66 } 67 68 if v := stateMgr.State(); v == nil { 69 lockId, err := stateMgr.Lock(lockInfo) 70 if err != nil { 71 return nil, fmt.Errorf("Failed to lock state in etcd: %s.", err) 72 } 73 74 lockUnlock = func(parent error) error { 75 if err := stateMgr.Unlock(lockId); err != nil { 76 return fmt.Errorf(strings.TrimSpace(errStateUnlock), lockId, err) 77 } 78 return parent 79 } 80 81 if err := stateMgr.WriteState(states.NewState()); err != nil { 82 err = lockUnlock(err) 83 return nil, err 84 } 85 if err := stateMgr.PersistState(); err != nil { 86 err = lockUnlock(err) 87 return nil, err 88 } 89 } 90 91 if err := lockUnlock(nil); err != nil { 92 return nil, err 93 } 94 95 return stateMgr, nil 96 } 97 98 func (b *Backend) determineKey(name string) string { 99 return b.prefix + name 100 } 101 102 const errStateUnlock = ` 103 Error unlocking etcd state. Lock ID: %s 104 105 Error: %s 106 107 You may have to force-unlock this state in order to use it again. 108 `