b30f78f66a
* Ignore errors from rollback manager invocations During reload and mount move operations, we want to ensure that errors created by the final Rollback are not fatal (which risk failing replication in Enterprise when the core/mounts table gets invalidated). This mirrors the behavior of the periodic rollback manager, which only logs the error. This updates the noop backend to allow failing just rollback operations, which we can use in tests to verify this behavior and ensure the core operations (plugin reload, plugin move, and seal/unseal) are not broken by this. Note that most of these operations were asynchronous from the client's PoV and thus did not fail anyways prior to this change. * Add changelog entry * Update vault/external_tests/router/router_ext_test.go --------- Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com> Co-authored-by: Alexander Scheel <alex.scheel@hashicorp.com> Co-authored-by: Nick Cabatoff <ncabatoff@hashicorp.com>
156 lines
3.5 KiB
Go
156 lines
3.5 KiB
Go
// Copyright (c) HashiCorp, Inc.
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
package vault
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"sync"
|
|
"time"
|
|
|
|
log "github.com/hashicorp/go-hclog"
|
|
"github.com/hashicorp/vault/sdk/logical"
|
|
)
|
|
|
|
type RouterTestHandlerFunc func(context.Context, *logical.Request) (*logical.Response, error)
|
|
|
|
type NoopBackend struct {
|
|
sync.Mutex
|
|
|
|
Root []string
|
|
Login []string
|
|
Paths []string
|
|
Requests []*logical.Request
|
|
Response *logical.Response
|
|
RequestHandler RouterTestHandlerFunc
|
|
Invalidations []string
|
|
DefaultLeaseTTL time.Duration
|
|
MaxLeaseTTL time.Duration
|
|
BackendType logical.BackendType
|
|
|
|
RollbackErrs bool
|
|
}
|
|
|
|
func NoopBackendFactory(_ context.Context, _ *logical.BackendConfig) (logical.Backend, error) {
|
|
return &NoopBackend{}, nil
|
|
}
|
|
|
|
func NoopBackendRollbackErrFactory(_ context.Context, _ *logical.BackendConfig) (logical.Backend, error) {
|
|
return &NoopBackend{RollbackErrs: true}, nil
|
|
}
|
|
|
|
func (n *NoopBackend) HandleRequest(ctx context.Context, req *logical.Request) (*logical.Response, error) {
|
|
if req.TokenEntry() != nil {
|
|
panic("got a non-nil TokenEntry")
|
|
}
|
|
|
|
if n.RollbackErrs && req.Operation == "rollback" {
|
|
return nil, fmt.Errorf("no-op backend rollback has erred out")
|
|
}
|
|
|
|
var err error
|
|
resp := n.Response
|
|
if n.RequestHandler != nil {
|
|
resp, err = n.RequestHandler(ctx, req)
|
|
}
|
|
|
|
n.Lock()
|
|
defer n.Unlock()
|
|
|
|
requestCopy := *req
|
|
n.Paths = append(n.Paths, req.Path)
|
|
n.Requests = append(n.Requests, &requestCopy)
|
|
if req.Storage == nil {
|
|
return nil, fmt.Errorf("missing view")
|
|
}
|
|
|
|
if req.Path == "panic" {
|
|
panic("as you command")
|
|
}
|
|
|
|
return resp, err
|
|
}
|
|
|
|
func (n *NoopBackend) HandleExistenceCheck(ctx context.Context, req *logical.Request) (bool, bool, error) {
|
|
return false, false, nil
|
|
}
|
|
|
|
func (n *NoopBackend) SpecialPaths() *logical.Paths {
|
|
return &logical.Paths{
|
|
Root: n.Root,
|
|
Unauthenticated: n.Login,
|
|
}
|
|
}
|
|
|
|
func (n *NoopBackend) System() logical.SystemView {
|
|
defaultLeaseTTLVal := time.Hour * 24
|
|
maxLeaseTTLVal := time.Hour * 24 * 32
|
|
if n.DefaultLeaseTTL > 0 {
|
|
defaultLeaseTTLVal = n.DefaultLeaseTTL
|
|
}
|
|
|
|
if n.MaxLeaseTTL > 0 {
|
|
maxLeaseTTLVal = n.MaxLeaseTTL
|
|
}
|
|
|
|
return logical.StaticSystemView{
|
|
DefaultLeaseTTLVal: defaultLeaseTTLVal,
|
|
MaxLeaseTTLVal: maxLeaseTTLVal,
|
|
}
|
|
}
|
|
|
|
func (n *NoopBackend) Cleanup(ctx context.Context) {
|
|
// noop
|
|
}
|
|
|
|
func (n *NoopBackend) InvalidateKey(ctx context.Context, k string) {
|
|
n.Invalidations = append(n.Invalidations, k)
|
|
}
|
|
|
|
func (n *NoopBackend) Setup(ctx context.Context, config *logical.BackendConfig) error {
|
|
return nil
|
|
}
|
|
|
|
func (n *NoopBackend) Logger() log.Logger {
|
|
return log.NewNullLogger()
|
|
}
|
|
|
|
func (n *NoopBackend) Initialize(ctx context.Context, req *logical.InitializationRequest) error {
|
|
return nil
|
|
}
|
|
|
|
func (n *NoopBackend) Type() logical.BackendType {
|
|
if n.BackendType == logical.TypeUnknown {
|
|
return logical.TypeLogical
|
|
}
|
|
return n.BackendType
|
|
}
|
|
|
|
// InitializableBackend is a backend that knows whether it has been initialized
|
|
// properly.
|
|
type InitializableBackend struct {
|
|
*NoopBackend
|
|
isInitialized bool
|
|
}
|
|
|
|
func (b *InitializableBackend) Initialize(ctx context.Context, req *logical.InitializationRequest) error {
|
|
if b.isInitialized {
|
|
return errors.New("already initialized")
|
|
}
|
|
|
|
// do a dummy write, to prove that the storage is not readonly
|
|
entry := &logical.StorageEntry{
|
|
Key: "initialize/zork",
|
|
Value: []byte("quux"),
|
|
}
|
|
err := req.Storage.Put(ctx, entry)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
b.isInitialized = true
|
|
return nil
|
|
}
|