Add path attributes to indicate when operations should forward (#7175)
This commit is contained in:
parent
0b5c7550a6
commit
fb4edc129e
|
@ -15,7 +15,8 @@ import (
|
|||
|
||||
"github.com/hashicorp/errwrap"
|
||||
log "github.com/hashicorp/go-hclog"
|
||||
multierror "github.com/hashicorp/go-multierror"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/hashicorp/vault/sdk/helper/consts"
|
||||
"github.com/hashicorp/vault/sdk/helper/entropy"
|
||||
"github.com/hashicorp/vault/sdk/helper/errutil"
|
||||
"github.com/hashicorp/vault/sdk/helper/license"
|
||||
|
@ -225,6 +226,19 @@ func (b *Backend) HandleRequest(ctx context.Context, req *logical.Request) (*log
|
|||
|
||||
if path.Operations != nil {
|
||||
if op, ok := path.Operations[req.Operation]; ok {
|
||||
|
||||
// Check whether this operation should be forwarded
|
||||
replState := b.System().ReplicationState()
|
||||
props := op.Properties()
|
||||
|
||||
if props.ForwardPerformanceStandby && replState.HasState(consts.ReplicationPerformanceStandby) {
|
||||
return nil, logical.ErrReadOnly
|
||||
}
|
||||
|
||||
if props.ForwardPerformanceSecondary && !b.System().LocalMount() && replState.HasState(consts.ReplicationPerformanceSecondary) {
|
||||
return nil, logical.ErrReadOnly
|
||||
}
|
||||
|
||||
callback = op.Handler()
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/vault/sdk/helper/consts"
|
||||
"github.com/hashicorp/vault/sdk/logical"
|
||||
)
|
||||
|
||||
|
@ -93,6 +94,7 @@ func TestBackendHandleRequest(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
system: &logical.StaticSystemView{},
|
||||
}
|
||||
|
||||
for _, path := range []string{"foo/bar", "foo/baz/handler", "foo/both/handler"} {
|
||||
|
@ -114,6 +116,98 @@ func TestBackendHandleRequest(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestBackendHandleRequest_Forwarding(t *testing.T) {
|
||||
tests := map[string]struct {
|
||||
fwdStandby bool
|
||||
fwdSecondary bool
|
||||
isLocal bool
|
||||
isStandby bool
|
||||
isSecondary bool
|
||||
expectFwd bool
|
||||
}{
|
||||
"no forward": {
|
||||
expectFwd: false,
|
||||
},
|
||||
"no forward, local restricted": {
|
||||
isSecondary: true,
|
||||
fwdSecondary: true,
|
||||
isLocal: true,
|
||||
expectFwd: false,
|
||||
},
|
||||
"no forward, forwarding not requested": {
|
||||
isSecondary: true,
|
||||
isStandby: true,
|
||||
expectFwd: false,
|
||||
},
|
||||
"forward, secondary": {
|
||||
fwdSecondary: true,
|
||||
isSecondary: true,
|
||||
expectFwd: true,
|
||||
},
|
||||
"forward, standby": {
|
||||
fwdStandby: true,
|
||||
isStandby: true,
|
||||
expectFwd: true,
|
||||
},
|
||||
"no forward, only secondary": {
|
||||
fwdSecondary: true,
|
||||
isStandby: true,
|
||||
expectFwd: false,
|
||||
},
|
||||
"no forward, only standby": {
|
||||
fwdStandby: true,
|
||||
isSecondary: true,
|
||||
expectFwd: false,
|
||||
},
|
||||
}
|
||||
|
||||
for name, test := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
var replState consts.ReplicationState
|
||||
if test.isStandby {
|
||||
replState.AddState(consts.ReplicationPerformanceStandby)
|
||||
}
|
||||
if test.isSecondary {
|
||||
replState.AddState(consts.ReplicationPerformanceSecondary)
|
||||
}
|
||||
|
||||
b := &Backend{
|
||||
Paths: []*Path{
|
||||
{
|
||||
Pattern: "foo",
|
||||
Operations: map[logical.Operation]OperationHandler{
|
||||
logical.ReadOperation: &PathOperation{
|
||||
Callback: func(ctx context.Context, req *logical.Request, data *FieldData) (*logical.Response, error) {
|
||||
return nil, nil
|
||||
},
|
||||
ForwardPerformanceSecondary: test.fwdSecondary,
|
||||
ForwardPerformanceStandby: test.fwdStandby,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
system: &logical.StaticSystemView{
|
||||
LocalMountVal: test.isLocal,
|
||||
ReplicationStateVal: replState,
|
||||
},
|
||||
}
|
||||
|
||||
_, err := b.HandleRequest(context.Background(), &logical.Request{
|
||||
Operation: logical.ReadOperation,
|
||||
Path: "foo",
|
||||
})
|
||||
|
||||
if !test.expectFwd && err != nil {
|
||||
t.Fatalf("unexpected err: %v", err)
|
||||
}
|
||||
if test.expectFwd && err != logical.ErrReadOnly {
|
||||
t.Fatalf("expected ErrReadOnly, got: %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBackendHandleRequest_badwrite(t *testing.T) {
|
||||
callback := func(ctx context.Context, req *logical.Request, data *FieldData) (*logical.Response, error) {
|
||||
return &logical.Response{
|
||||
|
|
|
@ -153,6 +153,14 @@ type OperationProperties struct {
|
|||
// Deprecated indicates that this operation should be avoided.
|
||||
Deprecated bool
|
||||
|
||||
// ForwardPerformanceStandby indicates that this path should not be processed
|
||||
// on a performance standby node, and should be forwarded to the active node instead.
|
||||
ForwardPerformanceStandby bool
|
||||
|
||||
// ForwardPerformanceSecondary indicates that this path should not be processed
|
||||
// on a performance secondary node, and should be forwarded to the active node instead.
|
||||
ForwardPerformanceSecondary bool
|
||||
|
||||
// DisplayAttrs provides hints for UI and documentation generators. They
|
||||
// will be included in OpenAPI output if set.
|
||||
DisplayAttrs *DisplayAttributes
|
||||
|
@ -206,13 +214,15 @@ type Response struct {
|
|||
|
||||
// PathOperation is a concrete implementation of OperationHandler.
|
||||
type PathOperation struct {
|
||||
Callback OperationFunc
|
||||
Summary string
|
||||
Description string
|
||||
Examples []RequestExample
|
||||
Responses map[int][]Response
|
||||
Unpublished bool
|
||||
Deprecated bool
|
||||
Callback OperationFunc
|
||||
Summary string
|
||||
Description string
|
||||
Examples []RequestExample
|
||||
Responses map[int][]Response
|
||||
Unpublished bool
|
||||
Deprecated bool
|
||||
ForwardPerformanceSecondary bool
|
||||
ForwardPerformanceStandby bool
|
||||
}
|
||||
|
||||
func (p *PathOperation) Handler() OperationFunc {
|
||||
|
@ -221,12 +231,14 @@ func (p *PathOperation) Handler() OperationFunc {
|
|||
|
||||
func (p *PathOperation) Properties() OperationProperties {
|
||||
return OperationProperties{
|
||||
Summary: strings.TrimSpace(p.Summary),
|
||||
Description: strings.TrimSpace(p.Description),
|
||||
Responses: p.Responses,
|
||||
Examples: p.Examples,
|
||||
Unpublished: p.Unpublished,
|
||||
Deprecated: p.Deprecated,
|
||||
Summary: strings.TrimSpace(p.Summary),
|
||||
Description: strings.TrimSpace(p.Description),
|
||||
Responses: p.Responses,
|
||||
Examples: p.Examples,
|
||||
Unpublished: p.Unpublished,
|
||||
Deprecated: p.Deprecated,
|
||||
ForwardPerformanceSecondary: p.ForwardPerformanceSecondary,
|
||||
ForwardPerformanceStandby: p.ForwardPerformanceStandby,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue