1package physical 2 3import ( 4 "context" 5 "strings" 6 "sync" 7 8 log "github.com/hashicorp/go-hclog" 9) 10 11const DefaultParallelOperations = 128 12 13// The operation type 14type Operation string 15 16const ( 17 DeleteOperation Operation = "delete" 18 GetOperation = "get" 19 ListOperation = "list" 20 PutOperation = "put" 21) 22 23const ( 24 ErrValueTooLarge = "put failed due to value being too large" 25) 26 27// ShutdownSignal 28type ShutdownChannel chan struct{} 29 30// Backend is the interface required for a physical 31// backend. A physical backend is used to durably store 32// data outside of Vault. As such, it is completely untrusted, 33// and is only accessed via a security barrier. The backends 34// must represent keys in a hierarchical manner. All methods 35// are expected to be thread safe. 36type Backend interface { 37 // Put is used to insert or update an entry 38 Put(ctx context.Context, entry *Entry) error 39 40 // Get is used to fetch an entry 41 Get(ctx context.Context, key string) (*Entry, error) 42 43 // Delete is used to permanently delete an entry 44 Delete(ctx context.Context, key string) error 45 46 // List is used to list all the keys under a given 47 // prefix, up to the next prefix. 48 List(ctx context.Context, prefix string) ([]string, error) 49} 50 51// HABackend is an extensions to the standard physical 52// backend to support high-availability. Vault only expects to 53// use mutual exclusion to allow multiple instances to act as a 54// hot standby for a leader that services all requests. 55type HABackend interface { 56 // LockWith is used for mutual exclusion based on the given key. 57 LockWith(key, value string) (Lock, error) 58 59 // Whether or not HA functionality is enabled 60 HAEnabled() bool 61} 62 63// ToggleablePurgemonster is an interface for backends that can toggle on or 64// off special functionality and/or support purging. This is only used for the 65// cache, don't use it for other things. 66type ToggleablePurgemonster interface { 67 Purge(ctx context.Context) 68 SetEnabled(bool) 69} 70 71// RedirectDetect is an optional interface that an HABackend 72// can implement. If they do, a redirect address can be automatically 73// detected. 74type RedirectDetect interface { 75 // DetectHostAddr is used to detect the host address 76 DetectHostAddr() (string, error) 77} 78 79// Callback signatures for RunServiceDiscovery 80type ActiveFunction func() bool 81type SealedFunction func() bool 82type PerformanceStandbyFunction func() bool 83 84// ServiceDiscovery is an optional interface that an HABackend can implement. 85// If they do, the state of a backend is advertised to the service discovery 86// network. 87type ServiceDiscovery interface { 88 // NotifyActiveStateChange is used by Core to notify a backend 89 // capable of ServiceDiscovery that this Vault instance has changed 90 // its status to active or standby. 91 NotifyActiveStateChange() error 92 93 // NotifySealedStateChange is used by Core to notify a backend 94 // capable of ServiceDiscovery that Vault has changed its Sealed 95 // status to sealed or unsealed. 96 NotifySealedStateChange() error 97 98 // NotifyPerformanceStandbyStateChange is used by Core to notify a backend 99 // capable of ServiceDiscovery that this Vault instance has changed it 100 // status to performance standby or standby. 101 NotifyPerformanceStandbyStateChange() error 102 103 // Run executes any background service discovery tasks until the 104 // shutdown channel is closed. 105 RunServiceDiscovery(waitGroup *sync.WaitGroup, shutdownCh ShutdownChannel, redirectAddr string, activeFunc ActiveFunction, sealedFunc SealedFunction, perfStandbyFunc PerformanceStandbyFunction) error 106} 107 108type Lock interface { 109 // Lock is used to acquire the given lock 110 // The stopCh is optional and if closed should interrupt the lock 111 // acquisition attempt. The return struct should be closed when 112 // leadership is lost. 113 Lock(stopCh <-chan struct{}) (<-chan struct{}, error) 114 115 // Unlock is used to release the lock 116 Unlock() error 117 118 // Returns the value of the lock and if it is held 119 Value() (bool, string, error) 120} 121 122// Factory is the factory function to create a physical backend. 123type Factory func(config map[string]string, logger log.Logger) (Backend, error) 124 125// PermitPool is used to limit maximum outstanding requests 126type PermitPool struct { 127 sem chan int 128} 129 130// NewPermitPool returns a new permit pool with the provided 131// number of permits 132func NewPermitPool(permits int) *PermitPool { 133 if permits < 1 { 134 permits = DefaultParallelOperations 135 } 136 return &PermitPool{ 137 sem: make(chan int, permits), 138 } 139} 140 141// Acquire returns when a permit has been acquired 142func (c *PermitPool) Acquire() { 143 c.sem <- 1 144} 145 146// Release returns a permit to the pool 147func (c *PermitPool) Release() { 148 <-c.sem 149} 150 151// Get number of requests in the permit pool 152func (c *PermitPool) CurrentPermits() int { 153 return len(c.sem) 154} 155 156// Prefixes is a shared helper function returns all parent 'folders' for a 157// given vault key. 158// e.g. for 'foo/bar/baz', it returns ['foo', 'foo/bar'] 159func Prefixes(s string) []string { 160 components := strings.Split(s, "/") 161 result := []string{} 162 for i := 1; i < len(components); i++ { 163 result = append(result, strings.Join(components[:i], "/")) 164 } 165 return result 166} 167