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