2023-03-15 16:00:52 +00:00
|
|
|
// Copyright (c) HashiCorp, Inc.
|
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
|
2015-03-02 18:48:53 +00:00
|
|
|
package physical
|
|
|
|
|
2016-04-26 03:10:32 +00:00
|
|
|
import (
|
2018-01-19 06:44:44 +00:00
|
|
|
"context"
|
2017-08-03 17:24:27 +00:00
|
|
|
"strings"
|
2016-08-19 20:45:17 +00:00
|
|
|
|
2018-04-03 00:46:59 +00:00
|
|
|
log "github.com/hashicorp/go-hclog"
|
2016-04-26 03:10:32 +00:00
|
|
|
)
|
2015-03-05 21:47:10 +00:00
|
|
|
|
2015-11-03 19:48:05 +00:00
|
|
|
const DefaultParallelOperations = 128
|
|
|
|
|
2017-02-17 14:15:35 +00:00
|
|
|
// The operation type
|
|
|
|
type Operation string
|
|
|
|
|
|
|
|
const (
|
|
|
|
DeleteOperation Operation = "delete"
|
|
|
|
GetOperation = "get"
|
|
|
|
ListOperation = "list"
|
|
|
|
PutOperation = "put"
|
|
|
|
)
|
|
|
|
|
2019-05-01 17:47:41 +00:00
|
|
|
const (
|
|
|
|
ErrValueTooLarge = "put failed due to value being too large"
|
2021-11-25 19:07:03 +00:00
|
|
|
ErrKeyTooLarge = "put failed due to key being too large"
|
2019-05-01 17:47:41 +00:00
|
|
|
)
|
|
|
|
|
2015-03-02 18:48:53 +00:00
|
|
|
// Backend is the interface required for a physical
|
|
|
|
// backend. A physical backend is used to durably store
|
2015-04-22 21:59:16 +00:00
|
|
|
// data outside of Vault. As such, it is completely untrusted,
|
2015-03-02 18:48:53 +00:00
|
|
|
// and is only accessed via a security barrier. The backends
|
|
|
|
// must represent keys in a hierarchical manner. All methods
|
|
|
|
// are expected to be thread safe.
|
|
|
|
type Backend interface {
|
|
|
|
// Put is used to insert or update an entry
|
2018-01-19 06:44:44 +00:00
|
|
|
Put(ctx context.Context, entry *Entry) error
|
2015-03-02 18:48:53 +00:00
|
|
|
|
|
|
|
// Get is used to fetch an entry
|
2018-01-19 06:44:44 +00:00
|
|
|
Get(ctx context.Context, key string) (*Entry, error)
|
2015-03-02 18:48:53 +00:00
|
|
|
|
|
|
|
// Delete is used to permanently delete an entry
|
2018-01-19 06:44:44 +00:00
|
|
|
Delete(ctx context.Context, key string) error
|
2015-03-02 18:48:53 +00:00
|
|
|
|
2018-08-13 21:02:31 +00:00
|
|
|
// List is used to list all the keys under a given
|
2015-03-02 18:48:53 +00:00
|
|
|
// prefix, up to the next prefix.
|
2018-01-19 06:44:44 +00:00
|
|
|
List(ctx context.Context, prefix string) ([]string, error)
|
2015-03-02 18:48:53 +00:00
|
|
|
}
|
|
|
|
|
2016-05-15 16:58:36 +00:00
|
|
|
// HABackend is an extensions to the standard physical
|
2015-04-14 18:49:46 +00:00
|
|
|
// backend to support high-availability. Vault only expects to
|
|
|
|
// use mutual exclusion to allow multiple instances to act as a
|
|
|
|
// hot standby for a leader that services all requests.
|
|
|
|
type HABackend interface {
|
|
|
|
// LockWith is used for mutual exclusion based on the given key.
|
2015-04-14 23:36:53 +00:00
|
|
|
LockWith(key, value string) (Lock, error)
|
2016-07-18 17:19:58 +00:00
|
|
|
|
|
|
|
// Whether or not HA functionality is enabled
|
|
|
|
HAEnabled() bool
|
2015-04-14 18:49:46 +00:00
|
|
|
}
|
|
|
|
|
2018-01-26 03:21:51 +00:00
|
|
|
// ToggleablePurgemonster is an interface for backends that can toggle on or
|
|
|
|
// off special functionality and/or support purging. This is only used for the
|
|
|
|
// cache, don't use it for other things.
|
|
|
|
type ToggleablePurgemonster interface {
|
2018-01-19 06:44:44 +00:00
|
|
|
Purge(ctx context.Context)
|
2018-01-26 03:21:51 +00:00
|
|
|
SetEnabled(bool)
|
2017-01-06 20:42:18 +00:00
|
|
|
}
|
|
|
|
|
2016-08-15 13:42:42 +00:00
|
|
|
// RedirectDetect is an optional interface that an HABackend
|
|
|
|
// can implement. If they do, a redirect address can be automatically
|
2015-05-02 22:34:29 +00:00
|
|
|
// detected.
|
2016-08-15 13:42:42 +00:00
|
|
|
type RedirectDetect interface {
|
2015-05-02 22:34:29 +00:00
|
|
|
// DetectHostAddr is used to detect the host address
|
|
|
|
DetectHostAddr() (string, error)
|
2016-04-23 02:55:17 +00:00
|
|
|
}
|
|
|
|
|
2015-04-14 18:49:46 +00:00
|
|
|
type Lock interface {
|
|
|
|
// Lock is used to acquire the given lock
|
|
|
|
// The stopCh is optional and if closed should interrupt the lock
|
|
|
|
// acquisition attempt. The return struct should be closed when
|
|
|
|
// leadership is lost.
|
|
|
|
Lock(stopCh <-chan struct{}) (<-chan struct{}, error)
|
|
|
|
|
|
|
|
// Unlock is used to release the lock
|
|
|
|
Unlock() error
|
2015-04-14 23:36:53 +00:00
|
|
|
|
|
|
|
// Returns the value of the lock and if it is held
|
|
|
|
Value() (bool, string, error)
|
2015-04-14 18:49:46 +00:00
|
|
|
}
|
|
|
|
|
2015-03-05 21:47:10 +00:00
|
|
|
// Factory is the factory function to create a physical backend.
|
2016-08-19 20:45:17 +00:00
|
|
|
type Factory func(config map[string]string, logger log.Logger) (Backend, error)
|
2015-03-05 21:47:10 +00:00
|
|
|
|
2016-11-28 23:34:58 +00:00
|
|
|
// PermitPool is used to limit maximum outstanding requests
|
2015-11-03 16:47:16 +00:00
|
|
|
type PermitPool struct {
|
2015-11-04 17:27:13 +00:00
|
|
|
sem chan int
|
2015-11-03 16:47:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewPermitPool returns a new permit pool with the provided
|
|
|
|
// number of permits
|
|
|
|
func NewPermitPool(permits int) *PermitPool {
|
|
|
|
if permits < 1 {
|
2015-11-03 19:48:05 +00:00
|
|
|
permits = DefaultParallelOperations
|
2015-11-03 16:47:16 +00:00
|
|
|
}
|
|
|
|
return &PermitPool{
|
2015-11-04 17:27:13 +00:00
|
|
|
sem: make(chan int, permits),
|
2015-11-03 16:47:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Acquire returns when a permit has been acquired
|
|
|
|
func (c *PermitPool) Acquire() {
|
2015-11-04 17:27:13 +00:00
|
|
|
c.sem <- 1
|
2015-11-03 16:47:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Release returns a permit to the pool
|
|
|
|
func (c *PermitPool) Release() {
|
2015-11-04 17:27:13 +00:00
|
|
|
<-c.sem
|
2015-11-03 16:47:16 +00:00
|
|
|
}
|
2017-08-03 17:24:27 +00:00
|
|
|
|
2019-09-04 18:33:16 +00:00
|
|
|
// Get number of requests in the permit pool
|
|
|
|
func (c *PermitPool) CurrentPermits() int {
|
|
|
|
return len(c.sem)
|
|
|
|
}
|
|
|
|
|
2017-08-03 17:24:27 +00:00
|
|
|
// Prefixes is a shared helper function returns all parent 'folders' for a
|
|
|
|
// given vault key.
|
|
|
|
// e.g. for 'foo/bar/baz', it returns ['foo', 'foo/bar']
|
|
|
|
func Prefixes(s string) []string {
|
|
|
|
components := strings.Split(s, "/")
|
|
|
|
result := []string{}
|
|
|
|
for i := 1; i < len(components); i++ {
|
|
|
|
result = append(result, strings.Join(components[:i], "/"))
|
|
|
|
}
|
|
|
|
return result
|
|
|
|
}
|