Adds replication state helper to framework.Backend (#21743)

* Adds replication state helper to framework.Backend

* Fix test

* adds changelog
This commit is contained in:
Austin Gebauer 2023-07-11 15:22:28 -07:00 committed by GitHub
parent 11691b3b37
commit bf19846b18
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 29 additions and 15 deletions

View file

@ -12,7 +12,6 @@ import (
"github.com/aws/aws-sdk-go/service/iam/iamiface"
"github.com/aws/aws-sdk-go/service/sts/stsiface"
"github.com/hashicorp/vault/sdk/framework"
"github.com/hashicorp/vault/sdk/helper/consts"
"github.com/hashicorp/vault/sdk/logical"
"github.com/hashicorp/vault/sdk/queue"
)
@ -32,7 +31,7 @@ func Factory(ctx context.Context, conf *logical.BackendConfig) (logical.Backend,
return b, nil
}
func Backend(conf *logical.BackendConfig) *backend {
func Backend(_ *logical.BackendConfig) *backend {
var b backend
b.credRotationQueue = queue.New()
b.Backend = &framework.Backend{
@ -67,11 +66,7 @@ func Backend(conf *logical.BackendConfig) *backend {
WALRollback: b.walRollback,
WALRollbackMinAge: minAwsUserRollbackAge,
PeriodicFunc: func(ctx context.Context, req *logical.Request) error {
repState := conf.System.ReplicationState()
if (conf.System.LocalMount() ||
!repState.HasState(consts.ReplicationPerformanceSecondary)) &&
!repState.HasState(consts.ReplicationDRSecondary) &&
!repState.HasState(consts.ReplicationPerformanceStandby) {
if b.WriteSafeReplicationState() {
return b.rotateExpiredStaticCreds(ctx, req)
}
return nil

View file

@ -68,7 +68,7 @@ func Factory(ctx context.Context, conf *logical.BackendConfig) (logical.Backend,
b.credRotationQueue = queue.New()
// Load queue and kickoff new periodic ticker
go b.initQueue(b.queueCtx, conf, conf.System.ReplicationState())
go b.initQueue(b.queueCtx, conf)
// collect metrics on number of plugin instances
var err error

View file

@ -13,7 +13,6 @@ import (
"github.com/hashicorp/go-secure-stdlib/strutil"
v5 "github.com/hashicorp/vault/sdk/database/dbplugin/v5"
"github.com/hashicorp/vault/sdk/framework"
"github.com/hashicorp/vault/sdk/helper/consts"
"github.com/hashicorp/vault/sdk/helper/locksutil"
"github.com/hashicorp/vault/sdk/logical"
"github.com/hashicorp/vault/sdk/queue"
@ -517,14 +516,12 @@ func (b *databaseBackend) setStaticAccount(ctx context.Context, s logical.Storag
// not wait for success or failure of it's tasks before continuing. This is to
// avoid blocking the mount process while loading and evaluating existing roles,
// etc.
func (b *databaseBackend) initQueue(ctx context.Context, conf *logical.BackendConfig, replicationState consts.ReplicationState) {
func (b *databaseBackend) initQueue(ctx context.Context, conf *logical.BackendConfig) {
// Verify this mount is on the primary server, or is a local mount. If not, do
// not create a queue or launch a ticker. Both processing the WAL list and
// populating the queue are done sequentially and before launching a
// go-routine to run the periodic ticker.
if (conf.System.LocalMount() || !replicationState.HasState(consts.ReplicationPerformanceSecondary)) &&
!replicationState.HasState(consts.ReplicationDRSecondary) &&
!replicationState.HasState(consts.ReplicationPerformanceStandby) {
if b.WriteSafeReplicationState() {
b.Logger().Info("initializing database rotation queue")
// Poll for a PutWAL call that does not return a "read-only storage" error.

View file

@ -20,7 +20,6 @@ import (
postgreshelper "github.com/hashicorp/vault/helper/testhelpers/postgresql"
v5 "github.com/hashicorp/vault/sdk/database/dbplugin/v5"
"github.com/hashicorp/vault/sdk/framework"
"github.com/hashicorp/vault/sdk/helper/consts"
"github.com/hashicorp/vault/sdk/helper/dbtxn"
"github.com/hashicorp/vault/sdk/helper/pluginutil"
"github.com/hashicorp/vault/sdk/logical"
@ -1224,7 +1223,7 @@ func TestStoredWALsCorrectlyProcessed(t *testing.T) {
b.credRotationQueue = queue.New()
// Now finish the startup process by populating the queue, which should discard the WAL
b.initQueue(ctx, config, consts.ReplicationUnknown)
b.initQueue(ctx, config)
if tc.shouldRotate {
requireWALs(t, storage, 1)

3
changelog/21743.txt Normal file
View file

@ -0,0 +1,3 @@
```release-note:improvement
sdk/framework: Adds replication state helper for backends to check for read-only storage
```

View file

@ -60,6 +60,11 @@ type Backend struct {
// InitializeFunc is the callback, which if set, will be invoked via
// Initialize() just after a plugin has been mounted.
//
// Note that storage writes should only occur on the active instance within a
// primary cluster or local mount on a performance secondary. If your InitializeFunc
// writes to storage, you can use the backend's WriteSafeReplicationState() method
// to prevent it from attempting to write on a Vault instance with read-only storage.
InitializeFunc InitializeFunc
// PeriodicFunc is the callback, which if set, will be invoked when the
@ -70,6 +75,11 @@ type Backend struct {
// entries in backend's storage, while the backend is still being used.
// (Note the difference between this action and `Clean`, which is
// invoked just before the backend is unmounted).
//
// Note that storage writes should only occur on the active instance within a
// primary cluster or local mount on a performance secondary. If your PeriodicFunc
// writes to storage, you can use the backend's WriteSafeReplicationState() method
// to prevent it from attempting to write on a Vault instance with read-only storage.
PeriodicFunc periodicFunc
// WALRollback is called when a WAL entry (see wal.go) has to be rolled
@ -466,6 +476,16 @@ func (b *Backend) Secret(k string) *Secret {
return nil
}
// WriteSafeReplicationState returns true if this backend instance is capable of writing
// to storage without receiving an ErrReadOnly error. The active instance in a primary
// cluster or a local mount on a performance secondary is capable of writing to storage.
func (b *Backend) WriteSafeReplicationState() bool {
replicationState := b.System().ReplicationState()
return (b.System().LocalMount() || !replicationState.HasState(consts.ReplicationPerformanceSecondary)) &&
!replicationState.HasState(consts.ReplicationDRSecondary) &&
!replicationState.HasState(consts.ReplicationPerformanceStandby)
}
func (b *Backend) init() {
b.pathsRe = make([]*regexp.Regexp, len(b.Paths))
for i, p := range b.Paths {