mirror of
https://github.com/hashicorp/vault.git
synced 2025-11-13 14:51:34 +01:00
transit cache is an Interface implemented by wrapped versions of sync… (#6225)
* transit cache is an Interface implemented by wrapped versions of syncmap and golang-lru * transit cache is an Interface implemented by wrapped versions of syncmap and golang-lru * changed some import paths to point to sdk * Apply suggestions from code review Co-Authored-By: Lexman42 <Lexman42@users.noreply.github.com> * updates docs with information on transit/cache-config endpoint * updates vendored files * fixes policy tests to actually use a cache where expected and renames the struct and storage path used for cache configurations to be more generic * updates document links * fixed a typo in a documentation link * changes cache_size to just size for the cache-config endpoint
This commit is contained in:
parent
4d0d70551d
commit
4ed616dacb
@ -4,20 +4,25 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/hashicorp/errwrap"
|
||||||
"github.com/hashicorp/vault/sdk/framework"
|
"github.com/hashicorp/vault/sdk/framework"
|
||||||
"github.com/hashicorp/vault/sdk/helper/keysutil"
|
"github.com/hashicorp/vault/sdk/helper/keysutil"
|
||||||
"github.com/hashicorp/vault/sdk/logical"
|
"github.com/hashicorp/vault/sdk/logical"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Factory(ctx context.Context, conf *logical.BackendConfig) (logical.Backend, error) {
|
func Factory(ctx context.Context, conf *logical.BackendConfig) (logical.Backend, error) {
|
||||||
b := Backend(conf)
|
|
||||||
|
b, err := Backend(ctx, conf)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
if err := b.Setup(ctx, conf); err != nil {
|
if err := b.Setup(ctx, conf); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func Backend(conf *logical.BackendConfig) *backend {
|
func Backend(ctx context.Context, conf *logical.BackendConfig) (*backend, error) {
|
||||||
var b backend
|
var b backend
|
||||||
b.Backend = &framework.Backend{
|
b.Backend = &framework.Backend{
|
||||||
PathsSpecial: &logical.Paths{
|
PathsSpecial: &logical.Paths{
|
||||||
@ -47,6 +52,7 @@ func Backend(conf *logical.BackendConfig) *backend {
|
|||||||
b.pathBackup(),
|
b.pathBackup(),
|
||||||
b.pathRestore(),
|
b.pathRestore(),
|
||||||
b.pathTrim(),
|
b.pathTrim(),
|
||||||
|
b.pathCacheConfig(),
|
||||||
},
|
},
|
||||||
|
|
||||||
Secrets: []*framework.Secret{},
|
Secrets: []*framework.Secret{},
|
||||||
@ -54,9 +60,24 @@ func Backend(conf *logical.BackendConfig) *backend {
|
|||||||
BackendType: logical.TypeLogical,
|
BackendType: logical.TypeLogical,
|
||||||
}
|
}
|
||||||
|
|
||||||
b.lm = keysutil.NewLockManager(conf.System.CachingDisabled())
|
// determine cacheSize to use. Defaults to 0 which means unlimited
|
||||||
|
cacheSize := 0
|
||||||
|
useCache := !conf.System.CachingDisabled()
|
||||||
|
if useCache {
|
||||||
|
var err error
|
||||||
|
cacheSize, err = GetCacheSizeFromStorage(ctx, conf.StorageView)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errwrap.Wrapf("Error retrieving cache size from storage: {{err}}", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return &b
|
var err error
|
||||||
|
b.lm, err = keysutil.NewLockManager(useCache, cacheSize)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &b, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type backend struct {
|
type backend struct {
|
||||||
@ -64,6 +85,22 @@ type backend struct {
|
|||||||
lm *keysutil.LockManager
|
lm *keysutil.LockManager
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetCacheSizeFromStorage(ctx context.Context, s logical.Storage) (int, error) {
|
||||||
|
size := 0
|
||||||
|
entry, err := s.Get(ctx, "config/cache")
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if entry != nil {
|
||||||
|
var storedCache configCache
|
||||||
|
if err := entry.DecodeJSON(&storedCache); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
size = storedCache.Size
|
||||||
|
}
|
||||||
|
return size, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (b *backend) invalidate(_ context.Context, key string) {
|
func (b *backend) invalidate(_ context.Context, key string) {
|
||||||
if b.Logger().IsDebug() {
|
if b.Logger().IsDebug() {
|
||||||
b.Logger().Debug("invalidating key", "key", key)
|
b.Logger().Debug("invalidating key", "key", key)
|
||||||
|
|||||||
@ -30,7 +30,7 @@ func createBackendWithStorage(t *testing.T) (*backend, logical.Storage) {
|
|||||||
config := logical.TestBackendConfig()
|
config := logical.TestBackendConfig()
|
||||||
config.StorageView = &logical.InmemStorage{}
|
config.StorageView = &logical.InmemStorage{}
|
||||||
|
|
||||||
b := Backend(config)
|
b, _ := Backend(context.Background(), config)
|
||||||
if b == nil {
|
if b == nil {
|
||||||
t.Fatalf("failed to create backend")
|
t.Fatalf("failed to create backend")
|
||||||
}
|
}
|
||||||
@ -50,7 +50,7 @@ func createBackendWithSysView(t *testing.T) (*backend, logical.Storage) {
|
|||||||
System: sysView,
|
System: sysView,
|
||||||
}
|
}
|
||||||
|
|
||||||
b := Backend(conf)
|
b, _ := Backend(context.Background(), conf)
|
||||||
if b == nil {
|
if b == nil {
|
||||||
t.Fatal("failed to create backend")
|
t.Fatal("failed to create backend")
|
||||||
}
|
}
|
||||||
@ -63,6 +63,49 @@ func createBackendWithSysView(t *testing.T) (*backend, logical.Storage) {
|
|||||||
return b, storage
|
return b, storage
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func createBackendWithSysViewWithStorage(t *testing.T, s logical.Storage) *backend {
|
||||||
|
sysView := logical.TestSystemView()
|
||||||
|
|
||||||
|
conf := &logical.BackendConfig{
|
||||||
|
StorageView: s,
|
||||||
|
System: sysView,
|
||||||
|
}
|
||||||
|
|
||||||
|
b, _ := Backend(context.Background(), conf)
|
||||||
|
if b == nil {
|
||||||
|
t.Fatal("failed to create backend")
|
||||||
|
}
|
||||||
|
|
||||||
|
err := b.Backend.Setup(context.Background(), conf)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func createBackendWithForceNoCacheWithSysViewWithStorage(t *testing.T, s logical.Storage) *backend {
|
||||||
|
sysView := logical.TestSystemView()
|
||||||
|
sysView.CachingDisabledVal = true
|
||||||
|
|
||||||
|
conf := &logical.BackendConfig{
|
||||||
|
StorageView: s,
|
||||||
|
System: sysView,
|
||||||
|
}
|
||||||
|
|
||||||
|
b, _ := Backend(context.Background(), conf)
|
||||||
|
if b == nil {
|
||||||
|
t.Fatal("failed to create backend")
|
||||||
|
}
|
||||||
|
|
||||||
|
err := b.Backend.Setup(context.Background(), conf)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
func TestTransit_RSA(t *testing.T) {
|
func TestTransit_RSA(t *testing.T) {
|
||||||
testTransit_RSA(t, "rsa-2048")
|
testTransit_RSA(t, "rsa-2048")
|
||||||
testTransit_RSA(t, "rsa-4096")
|
testTransit_RSA(t, "rsa-4096")
|
||||||
@ -1294,16 +1337,17 @@ func testConvergentEncryptionCommon(t *testing.T, ver int, keyType keysutil.KeyT
|
|||||||
func TestPolicyFuzzing(t *testing.T) {
|
func TestPolicyFuzzing(t *testing.T) {
|
||||||
var be *backend
|
var be *backend
|
||||||
sysView := logical.TestSystemView()
|
sysView := logical.TestSystemView()
|
||||||
|
sysView.CachingDisabledVal = true
|
||||||
conf := &logical.BackendConfig{
|
conf := &logical.BackendConfig{
|
||||||
System: sysView,
|
System: sysView,
|
||||||
}
|
}
|
||||||
|
|
||||||
be = Backend(conf)
|
be, _ = Backend(context.Background(), conf)
|
||||||
be.Setup(context.Background(), conf)
|
be.Setup(context.Background(), conf)
|
||||||
testPolicyFuzzingCommon(t, be)
|
testPolicyFuzzingCommon(t, be)
|
||||||
|
|
||||||
sysView.CachingDisabledVal = true
|
sysView.CachingDisabledVal = true
|
||||||
be = Backend(conf)
|
be, _ = Backend(context.Background(), conf)
|
||||||
be.Setup(context.Background(), conf)
|
be.Setup(context.Background(), conf)
|
||||||
testPolicyFuzzingCommon(t, be)
|
testPolicyFuzzingCommon(t, be)
|
||||||
}
|
}
|
||||||
|
|||||||
106
builtin/logical/transit/path_cache_config.go
Normal file
106
builtin/logical/transit/path_cache_config.go
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
package transit
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/hashicorp/vault/sdk/framework"
|
||||||
|
"github.com/hashicorp/vault/sdk/logical"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (b *backend) pathCacheConfig() *framework.Path {
|
||||||
|
return &framework.Path{
|
||||||
|
Pattern: "cache-config",
|
||||||
|
Fields: map[string]*framework.FieldSchema{
|
||||||
|
"size": &framework.FieldSchema{
|
||||||
|
Type: framework.TypeInt,
|
||||||
|
Required: false,
|
||||||
|
Default: 0,
|
||||||
|
Description: `Size of cache, use 0 for an unlimited cache size, defaults to 0`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
Operations: map[logical.Operation]framework.OperationHandler{
|
||||||
|
logical.ReadOperation: &framework.PathOperation{
|
||||||
|
Callback: b.pathCacheConfigRead,
|
||||||
|
Summary: "Returns the size of the active cache",
|
||||||
|
},
|
||||||
|
|
||||||
|
logical.UpdateOperation: &framework.PathOperation{
|
||||||
|
Callback: b.pathCacheConfigWrite,
|
||||||
|
Summary: "Configures a new cache of the specified size",
|
||||||
|
},
|
||||||
|
|
||||||
|
logical.CreateOperation: &framework.PathOperation{
|
||||||
|
Callback: b.pathCacheConfigWrite,
|
||||||
|
Summary: "Configures a new cache of the specified size",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
HelpSynopsis: pathCacheConfigHelpSyn,
|
||||||
|
HelpDescription: pathCacheConfigHelpDesc,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *backend) pathCacheConfigWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
|
||||||
|
// get target size
|
||||||
|
cacheSize := d.Get("size").(int)
|
||||||
|
if cacheSize < 0 {
|
||||||
|
return logical.ErrorResponse("size must be greater or equal to 0"), logical.ErrInvalidRequest
|
||||||
|
}
|
||||||
|
|
||||||
|
// store cache size
|
||||||
|
entry, err := logical.StorageEntryJSON("config/cache", &configCache{
|
||||||
|
Size: cacheSize,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := req.Storage.Put(ctx, entry); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := &logical.Response{
|
||||||
|
Warnings: []string{"cache configurations will be applied when this backend is restarted"},
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type configCache struct {
|
||||||
|
Size int `json:"size"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *backend) pathCacheConfigRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
|
||||||
|
// error if no cache is configured
|
||||||
|
if !b.lm.GetUseCache() {
|
||||||
|
return nil, errors.New(
|
||||||
|
"caching is disabled for this transit mount",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare current and stored cache sizes. If they are different warn the user.
|
||||||
|
currentCacheSize := b.lm.GetCacheSize()
|
||||||
|
storedCacheSize, err := GetCacheSizeFromStorage(ctx, req.Storage)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := &logical.Response{
|
||||||
|
Data: map[string]interface{}{
|
||||||
|
"size": storedCacheSize,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if currentCacheSize != storedCacheSize {
|
||||||
|
resp.Warnings = []string{"This cache size will not be applied until the transit mount is reloaded"}
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const pathCacheConfigHelpSyn = `Configure caching strategy`
|
||||||
|
|
||||||
|
const pathCacheConfigHelpDesc = `
|
||||||
|
This path is used to configure and query the cache size of the active cache, a size of 0 means unlimited.
|
||||||
|
`
|
||||||
80
builtin/logical/transit/path_cache_config_test.go
Normal file
80
builtin/logical/transit/path_cache_config_test.go
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
package transit
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/hashicorp/vault/sdk/logical"
|
||||||
|
)
|
||||||
|
|
||||||
|
const targetCacheSize = 12345
|
||||||
|
|
||||||
|
func TestTransit_CacheConfig(t *testing.T) {
|
||||||
|
b1, storage := createBackendWithSysView(t)
|
||||||
|
|
||||||
|
doReq := func(b *backend, req *logical.Request) *logical.Response {
|
||||||
|
resp, err := b.HandleRequest(context.Background(), req)
|
||||||
|
if err != nil || (resp != nil && resp.IsError()) {
|
||||||
|
t.Fatalf("got err:\n%#v\nreq:\n%#v\n", err, *req)
|
||||||
|
}
|
||||||
|
return resp
|
||||||
|
}
|
||||||
|
|
||||||
|
doErrReq := func(b *backend, req *logical.Request) {
|
||||||
|
resp, err := b.HandleRequest(context.Background(), req)
|
||||||
|
if err == nil {
|
||||||
|
if resp == nil || !resp.IsError() {
|
||||||
|
t.Fatalf("expected error; req:\n%#v\n", *req)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
validateResponse := func(resp *logical.Response, expectedCacheSize int, expectedWarning bool) {
|
||||||
|
actualCacheSize, ok := resp.Data["size"].(int)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("No size returned")
|
||||||
|
}
|
||||||
|
if expectedCacheSize != actualCacheSize {
|
||||||
|
t.Fatalf("testAccReadCacheConfig expected: %d got: %d", expectedCacheSize, actualCacheSize)
|
||||||
|
}
|
||||||
|
// check for the presence/absence of warnings - warnings are expected if a cache size has been
|
||||||
|
// configured but not yet applied by reloading the plugin
|
||||||
|
warningCheckPass := expectedWarning == (len(resp.Warnings) > 0)
|
||||||
|
if !warningCheckPass {
|
||||||
|
t.Fatalf(
|
||||||
|
"testAccSteporeadCacheConfig warnings error.\n"+
|
||||||
|
"expect warnings: %t but number of warnings was: %d",
|
||||||
|
expectedWarning, len(resp.Warnings),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
writeReq := &logical.Request{
|
||||||
|
Storage: storage,
|
||||||
|
Operation: logical.UpdateOperation,
|
||||||
|
Path: "cache-config",
|
||||||
|
Data: map[string]interface{}{
|
||||||
|
"size": targetCacheSize,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
readReq := &logical.Request{
|
||||||
|
Storage: storage,
|
||||||
|
Operation: logical.ReadOperation,
|
||||||
|
Path: "cache-config",
|
||||||
|
}
|
||||||
|
|
||||||
|
// test steps
|
||||||
|
// b1 should spin up with an unlimited cache
|
||||||
|
validateResponse(doReq(b1, readReq), 0, false)
|
||||||
|
doReq(b1, writeReq)
|
||||||
|
validateResponse(doReq(b1, readReq), targetCacheSize, true)
|
||||||
|
|
||||||
|
// b2 should spin up with a configured cache
|
||||||
|
b2 := createBackendWithSysViewWithStorage(t, storage)
|
||||||
|
validateResponse(doReq(b2, readReq), targetCacheSize, false)
|
||||||
|
|
||||||
|
// b3 enables transit without a cache, trying to read it should error
|
||||||
|
b3 := createBackendWithForceNoCacheWithSysViewWithStorage(t, storage)
|
||||||
|
doErrReq(b3, readReq)
|
||||||
|
}
|
||||||
@ -14,8 +14,9 @@ func TestTransit_Random(t *testing.T) {
|
|||||||
var b *backend
|
var b *backend
|
||||||
sysView := logical.TestSystemView()
|
sysView := logical.TestSystemView()
|
||||||
storage := &logical.InmemStorage{}
|
storage := &logical.InmemStorage{}
|
||||||
|
sysView.CachingDisabledVal = true
|
||||||
|
|
||||||
b = Backend(&logical.BackendConfig{
|
b, _ = Backend(context.Background(), &logical.BackendConfig{
|
||||||
StorageView: storage,
|
StorageView: storage,
|
||||||
System: sysView,
|
System: sysView,
|
||||||
})
|
})
|
||||||
|
|||||||
8
sdk/helper/keysutil/cache.go
Normal file
8
sdk/helper/keysutil/cache.go
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
package keysutil
|
||||||
|
|
||||||
|
type Cache interface {
|
||||||
|
Delete(key interface{})
|
||||||
|
Load(key interface{}) (value interface{}, ok bool)
|
||||||
|
Store(key, value interface{})
|
||||||
|
Size() int
|
||||||
|
}
|
||||||
@ -55,21 +55,44 @@ type PolicyRequest struct {
|
|||||||
|
|
||||||
type LockManager struct {
|
type LockManager struct {
|
||||||
useCache bool
|
useCache bool
|
||||||
// If caching is enabled, the map of name to in-memory policy cache
|
cache Cache
|
||||||
cache sync.Map
|
|
||||||
|
|
||||||
keyLocks []*locksutil.LockEntry
|
keyLocks []*locksutil.LockEntry
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewLockManager(cacheDisabled bool) *LockManager {
|
func NewLockManager(useCache bool, cacheSize int) (*LockManager, error) {
|
||||||
|
// determine the type of cache to create
|
||||||
|
var cache Cache
|
||||||
|
switch {
|
||||||
|
case !useCache:
|
||||||
|
case cacheSize < 0:
|
||||||
|
return nil, errors.New("cache size must be greater or equal to zero")
|
||||||
|
case cacheSize == 0:
|
||||||
|
cache = NewTransitSyncMap()
|
||||||
|
case cacheSize > 0:
|
||||||
|
newLRUCache, err := NewTransitLRU(cacheSize)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errwrap.Wrapf("failed to create cache: {{err}}", err)
|
||||||
|
}
|
||||||
|
cache = newLRUCache
|
||||||
|
}
|
||||||
|
|
||||||
lm := &LockManager{
|
lm := &LockManager{
|
||||||
useCache: !cacheDisabled,
|
useCache: useCache,
|
||||||
|
cache: cache,
|
||||||
keyLocks: locksutil.CreateLocks(),
|
keyLocks: locksutil.CreateLocks(),
|
||||||
}
|
}
|
||||||
return lm
|
|
||||||
|
return lm, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (lm *LockManager) CacheActive() bool {
|
func (lm *LockManager) GetCacheSize() int {
|
||||||
|
if !lm.useCache {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return lm.cache.Size()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lm *LockManager) GetUseCache() bool {
|
||||||
return lm.useCache
|
return lm.useCache
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,7 +201,6 @@ func (lm *LockManager) RestorePolicy(ctx context.Context, storage logical.Storag
|
|||||||
if lm.useCache {
|
if lm.useCache {
|
||||||
lm.cache.Store(name, keyData.Policy)
|
lm.cache.Store(name, keyData.Policy)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,7 +208,7 @@ func (lm *LockManager) BackupPolicy(ctx context.Context, storage logical.Storage
|
|||||||
var p *Policy
|
var p *Policy
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
// Backup writes information about when the bacup took place, so we get an
|
// Backup writes information about when the backup took place, so we get an
|
||||||
// exclusive lock here
|
// exclusive lock here
|
||||||
lock := locksutil.LockForKey(lm.keyLocks, name)
|
lock := locksutil.LockForKey(lm.keyLocks, name)
|
||||||
lock.Lock()
|
lock.Lock()
|
||||||
|
|||||||
@ -52,8 +52,10 @@ func TestPolicy_KeyEntryMapUpgrade(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Test_KeyUpgrade(t *testing.T) {
|
func Test_KeyUpgrade(t *testing.T) {
|
||||||
testKeyUpgradeCommon(t, NewLockManager(false))
|
lockManagerWithCache, _ := NewLockManager(true, 0)
|
||||||
testKeyUpgradeCommon(t, NewLockManager(true))
|
lockManagerWithoutCache, _ := NewLockManager(false, 0)
|
||||||
|
testKeyUpgradeCommon(t, lockManagerWithCache)
|
||||||
|
testKeyUpgradeCommon(t, lockManagerWithoutCache)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testKeyUpgradeCommon(t *testing.T, lm *LockManager) {
|
func testKeyUpgradeCommon(t *testing.T, lm *LockManager) {
|
||||||
@ -97,8 +99,10 @@ func testKeyUpgradeCommon(t *testing.T, lm *LockManager) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Test_ArchivingUpgrade(t *testing.T) {
|
func Test_ArchivingUpgrade(t *testing.T) {
|
||||||
testArchivingUpgradeCommon(t, NewLockManager(false))
|
lockManagerWithCache, _ := NewLockManager(true, 0)
|
||||||
testArchivingUpgradeCommon(t, NewLockManager(true))
|
lockManagerWithoutCache, _ := NewLockManager(false, 0)
|
||||||
|
testArchivingUpgradeCommon(t, lockManagerWithCache)
|
||||||
|
testArchivingUpgradeCommon(t, lockManagerWithoutCache)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testArchivingUpgradeCommon(t *testing.T, lm *LockManager) {
|
func testArchivingUpgradeCommon(t *testing.T, lm *LockManager) {
|
||||||
@ -255,8 +259,10 @@ func testArchivingUpgradeCommon(t *testing.T, lm *LockManager) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Test_Archiving(t *testing.T) {
|
func Test_Archiving(t *testing.T) {
|
||||||
testArchivingCommon(t, NewLockManager(false))
|
lockManagerWithCache, _ := NewLockManager(true, 0)
|
||||||
testArchivingCommon(t, NewLockManager(true))
|
lockManagerWithoutCache, _ := NewLockManager(false, 0)
|
||||||
|
testArchivingUpgradeCommon(t, lockManagerWithCache)
|
||||||
|
testArchivingUpgradeCommon(t, lockManagerWithoutCache)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testArchivingCommon(t *testing.T, lm *LockManager) {
|
func testArchivingCommon(t *testing.T, lm *LockManager) {
|
||||||
@ -420,7 +426,7 @@ func checkKeys(t *testing.T,
|
|||||||
|
|
||||||
func Test_StorageErrorSafety(t *testing.T) {
|
func Test_StorageErrorSafety(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
lm := NewLockManager(false)
|
lm, _ := NewLockManager(true, 0)
|
||||||
|
|
||||||
storage := &logical.InmemStorage{}
|
storage := &logical.InmemStorage{}
|
||||||
p, _, err := lm.GetPolicy(ctx, PolicyRequest{
|
p, _, err := lm.GetPolicy(ctx, PolicyRequest{
|
||||||
@ -468,7 +474,7 @@ func Test_StorageErrorSafety(t *testing.T) {
|
|||||||
|
|
||||||
func Test_BadUpgrade(t *testing.T) {
|
func Test_BadUpgrade(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
lm := NewLockManager(false)
|
lm, _ := NewLockManager(true, 0)
|
||||||
storage := &logical.InmemStorage{}
|
storage := &logical.InmemStorage{}
|
||||||
p, _, err := lm.GetPolicy(ctx, PolicyRequest{
|
p, _, err := lm.GetPolicy(ctx, PolicyRequest{
|
||||||
Upsert: true,
|
Upsert: true,
|
||||||
@ -533,7 +539,7 @@ func Test_BadUpgrade(t *testing.T) {
|
|||||||
|
|
||||||
func Test_BadArchive(t *testing.T) {
|
func Test_BadArchive(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
lm := NewLockManager(false)
|
lm, _ := NewLockManager(true, 0)
|
||||||
storage := &logical.InmemStorage{}
|
storage := &logical.InmemStorage{}
|
||||||
p, _, err := lm.GetPolicy(ctx, PolicyRequest{
|
p, _, err := lm.GetPolicy(ctx, PolicyRequest{
|
||||||
Upsert: true,
|
Upsert: true,
|
||||||
|
|||||||
29
sdk/helper/keysutil/transit_lru.go
Normal file
29
sdk/helper/keysutil/transit_lru.go
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package keysutil
|
||||||
|
|
||||||
|
import lru "github.com/hashicorp/golang-lru"
|
||||||
|
|
||||||
|
type TransitLRU struct {
|
||||||
|
size int
|
||||||
|
lru *lru.TwoQueueCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTransitLRU(size int) (*TransitLRU, error) {
|
||||||
|
lru, err := lru.New2Q(size)
|
||||||
|
return &TransitLRU{lru: lru, size: size}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *TransitLRU) Delete(key interface{}) {
|
||||||
|
c.lru.Remove(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *TransitLRU) Load(key interface{}) (value interface{}, ok bool) {
|
||||||
|
return c.lru.Get(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *TransitLRU) Store(key, value interface{}) {
|
||||||
|
c.lru.Add(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *TransitLRU) Size() int {
|
||||||
|
return c.size
|
||||||
|
}
|
||||||
29
sdk/helper/keysutil/transit_syncmap.go
Normal file
29
sdk/helper/keysutil/transit_syncmap.go
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package keysutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TransitSyncMap struct {
|
||||||
|
syncmap sync.Map
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTransitSyncMap() *TransitSyncMap {
|
||||||
|
return &TransitSyncMap{syncmap: sync.Map{}}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *TransitSyncMap) Delete(key interface{}) {
|
||||||
|
c.syncmap.Delete(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *TransitSyncMap) Load(key interface{}) (value interface{}, ok bool) {
|
||||||
|
return c.syncmap.Load(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *TransitSyncMap) Store(key, value interface{}) {
|
||||||
|
c.syncmap.Store(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *TransitSyncMap) Size() int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
8
vendor/github.com/hashicorp/vault/sdk/helper/keysutil/cache.go
generated
vendored
Normal file
8
vendor/github.com/hashicorp/vault/sdk/helper/keysutil/cache.go
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
package keysutil
|
||||||
|
|
||||||
|
type Cache interface {
|
||||||
|
Delete(key interface{})
|
||||||
|
Load(key interface{}) (value interface{}, ok bool)
|
||||||
|
Store(key, value interface{})
|
||||||
|
Size() int
|
||||||
|
}
|
||||||
40
vendor/github.com/hashicorp/vault/sdk/helper/keysutil/lock_manager.go
generated
vendored
40
vendor/github.com/hashicorp/vault/sdk/helper/keysutil/lock_manager.go
generated
vendored
@ -55,21 +55,44 @@ type PolicyRequest struct {
|
|||||||
|
|
||||||
type LockManager struct {
|
type LockManager struct {
|
||||||
useCache bool
|
useCache bool
|
||||||
// If caching is enabled, the map of name to in-memory policy cache
|
cache Cache
|
||||||
cache sync.Map
|
|
||||||
|
|
||||||
keyLocks []*locksutil.LockEntry
|
keyLocks []*locksutil.LockEntry
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewLockManager(cacheDisabled bool) *LockManager {
|
func NewLockManager(useCache bool, cacheSize int) (*LockManager, error) {
|
||||||
|
// determine the type of cache to create
|
||||||
|
var cache Cache
|
||||||
|
switch {
|
||||||
|
case !useCache:
|
||||||
|
case cacheSize < 0:
|
||||||
|
return nil, errors.New("cache size must be greater or equal to zero")
|
||||||
|
case cacheSize == 0:
|
||||||
|
cache = NewTransitSyncMap()
|
||||||
|
case cacheSize > 0:
|
||||||
|
newLRUCache, err := NewTransitLRU(cacheSize)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errwrap.Wrapf("failed to create cache: {{err}}", err)
|
||||||
|
}
|
||||||
|
cache = newLRUCache
|
||||||
|
}
|
||||||
|
|
||||||
lm := &LockManager{
|
lm := &LockManager{
|
||||||
useCache: !cacheDisabled,
|
useCache: useCache,
|
||||||
|
cache: cache,
|
||||||
keyLocks: locksutil.CreateLocks(),
|
keyLocks: locksutil.CreateLocks(),
|
||||||
}
|
}
|
||||||
return lm
|
|
||||||
|
return lm, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (lm *LockManager) CacheActive() bool {
|
func (lm *LockManager) GetCacheSize() int {
|
||||||
|
if !lm.useCache {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return lm.cache.Size()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lm *LockManager) GetUseCache() bool {
|
||||||
return lm.useCache
|
return lm.useCache
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,7 +201,6 @@ func (lm *LockManager) RestorePolicy(ctx context.Context, storage logical.Storag
|
|||||||
if lm.useCache {
|
if lm.useCache {
|
||||||
lm.cache.Store(name, keyData.Policy)
|
lm.cache.Store(name, keyData.Policy)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,7 +208,7 @@ func (lm *LockManager) BackupPolicy(ctx context.Context, storage logical.Storage
|
|||||||
var p *Policy
|
var p *Policy
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
// Backup writes information about when the bacup took place, so we get an
|
// Backup writes information about when the backup took place, so we get an
|
||||||
// exclusive lock here
|
// exclusive lock here
|
||||||
lock := locksutil.LockForKey(lm.keyLocks, name)
|
lock := locksutil.LockForKey(lm.keyLocks, name)
|
||||||
lock.Lock()
|
lock.Lock()
|
||||||
|
|||||||
29
vendor/github.com/hashicorp/vault/sdk/helper/keysutil/transit_lru.go
generated
vendored
Normal file
29
vendor/github.com/hashicorp/vault/sdk/helper/keysutil/transit_lru.go
generated
vendored
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package keysutil
|
||||||
|
|
||||||
|
import lru "github.com/hashicorp/golang-lru"
|
||||||
|
|
||||||
|
type TransitLRU struct {
|
||||||
|
size int
|
||||||
|
lru *lru.TwoQueueCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTransitLRU(size int) (*TransitLRU, error) {
|
||||||
|
lru, err := lru.New2Q(size)
|
||||||
|
return &TransitLRU{lru: lru, size: size}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *TransitLRU) Delete(key interface{}) {
|
||||||
|
c.lru.Remove(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *TransitLRU) Load(key interface{}) (value interface{}, ok bool) {
|
||||||
|
return c.lru.Get(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *TransitLRU) Store(key, value interface{}) {
|
||||||
|
c.lru.Add(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *TransitLRU) Size() int {
|
||||||
|
return c.size
|
||||||
|
}
|
||||||
29
vendor/github.com/hashicorp/vault/sdk/helper/keysutil/transit_syncmap.go
generated
vendored
Normal file
29
vendor/github.com/hashicorp/vault/sdk/helper/keysutil/transit_syncmap.go
generated
vendored
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package keysutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TransitSyncMap struct {
|
||||||
|
syncmap sync.Map
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTransitSyncMap() *TransitSyncMap {
|
||||||
|
return &TransitSyncMap{syncmap: sync.Map{}}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *TransitSyncMap) Delete(key interface{}) {
|
||||||
|
c.syncmap.Delete(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *TransitSyncMap) Load(key interface{}) (value interface{}, ok bool) {
|
||||||
|
return c.syncmap.Load(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *TransitSyncMap) Store(key, value interface{}) {
|
||||||
|
c.syncmap.Store(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *TransitSyncMap) Size() int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
@ -1252,3 +1252,64 @@ $ curl \
|
|||||||
--data @payload.json \
|
--data @payload.json \
|
||||||
http://127.0.0.1:8200/v1/transit/keys/my-key/trim
|
http://127.0.0.1:8200/v1/transit/keys/my-key/trim
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Configure Cache
|
||||||
|
|
||||||
|
This endpoint is used to configure the transit engine's cache. Note that configuration
|
||||||
|
changes will not be applied until the transit plugin is reloaded which can be achieved
|
||||||
|
using the [`/sys/plugins/reload/backend`][sys-plugin-reload-backend] endpoint.
|
||||||
|
|
||||||
|
| Method | Path |
|
||||||
|
| :------------------------- | :--------------------- |
|
||||||
|
| `POST` | `/transit/cache-config` |
|
||||||
|
|
||||||
|
### Parameters
|
||||||
|
|
||||||
|
- `size` `(int: 0)` - Specifies the size in terms of number of entries. A size of
|
||||||
|
`0` means unlimited. A _Least Recently Used_ (LRU) caching strategy is used for a
|
||||||
|
non-zero cache size.
|
||||||
|
|
||||||
|
### Sample Payload
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"size": 456
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Sample Request
|
||||||
|
|
||||||
|
```
|
||||||
|
$ curl \
|
||||||
|
--header "X-Vault-Token: ..."
|
||||||
|
--request POST \
|
||||||
|
--data @payload.json \
|
||||||
|
http://127.0.0.1:8200/v1/transit/cache-config
|
||||||
|
```
|
||||||
|
|
||||||
|
## Read Transit Cache Configuration
|
||||||
|
|
||||||
|
This endpoint retrieves configurations for the transit engine's cache.
|
||||||
|
|
||||||
|
| Method | Path |
|
||||||
|
| :------------------------- | :--------------------- |
|
||||||
|
| `GET` | `/transit/cache-config` |
|
||||||
|
|
||||||
|
### Sample Request
|
||||||
|
|
||||||
|
```
|
||||||
|
$ curl \
|
||||||
|
--header "X-Vault-Token: ..."
|
||||||
|
--request GET \
|
||||||
|
http://127.0.0.1:8200/v1/transit/cache-config
|
||||||
|
```
|
||||||
|
|
||||||
|
### Sample Response
|
||||||
|
|
||||||
|
```json
|
||||||
|
"data": {
|
||||||
|
"size": 0
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
[sys-plugin-reload-backend]: /api/system/plugins-reload-backend.html#reload-plugins
|
||||||
Loading…
x
Reference in New Issue
Block a user