mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-11-02 03:27:54 +00:00
Port activation flags with dynamic registration (#29237)
This commit is contained in:
3
changelog/29237.txt
Normal file
3
changelog/29237.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
```release-note:improvement
|
||||||
|
core: Add activation flags. A mechanism for users to opt in to new functionality at a convenient time. Previously used only in Enterprise for SecretSync, activation flags are now available in CE for future features to use.
|
||||||
|
```
|
||||||
142
helper/activationflags/activation_flags.go
Normal file
142
helper/activationflags/activation_flags.go
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
// Copyright (c) HashiCorp, Inc.
|
||||||
|
// SPDX-License-Identifier: BUSL-1.1
|
||||||
|
|
||||||
|
package activationflags
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"maps"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/hashicorp/vault/sdk/logical"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
storagePathActivationFlags = "activation-flags"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FeatureActivationFlags struct {
|
||||||
|
activationFlagsLock sync.RWMutex
|
||||||
|
storage logical.Storage
|
||||||
|
activationFlags map[string]bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewFeatureActivationFlags() *FeatureActivationFlags {
|
||||||
|
return &FeatureActivationFlags{
|
||||||
|
activationFlags: map[string]bool{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FeatureActivationFlags) Initialize(ctx context.Context, storage logical.Storage) error {
|
||||||
|
f.activationFlagsLock.Lock()
|
||||||
|
defer f.activationFlagsLock.Unlock()
|
||||||
|
|
||||||
|
if storage == nil {
|
||||||
|
return fmt.Errorf("unable to access storage")
|
||||||
|
}
|
||||||
|
|
||||||
|
f.storage = storage
|
||||||
|
|
||||||
|
entry, err := f.storage.Get(ctx, storagePathActivationFlags)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to get activation flags from storage: %w", err)
|
||||||
|
}
|
||||||
|
if entry == nil {
|
||||||
|
f.activationFlags = map[string]bool{}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var activationFlags map[string]bool
|
||||||
|
if err := entry.DecodeJSON(&activationFlags); err != nil {
|
||||||
|
return fmt.Errorf("failed to decode activation flags from storage: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
f.activationFlags = activationFlags
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get is the helper function called by the activation-flags API read endpoint. This reads the
|
||||||
|
// actual values from storage, then updates the in-memory cache of the activation-flags. It
|
||||||
|
// returns a slice of the feature names which have already been activated.
|
||||||
|
func (f *FeatureActivationFlags) Get(ctx context.Context) ([]string, error) {
|
||||||
|
f.activationFlagsLock.Lock()
|
||||||
|
defer f.activationFlagsLock.Unlock()
|
||||||
|
|
||||||
|
// Don't use nil slice declaration, we want the JSON to show "[]" instead of null
|
||||||
|
activated := []string{}
|
||||||
|
|
||||||
|
if f.storage == nil {
|
||||||
|
return activated, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
entry, err := f.storage.Get(ctx, storagePathActivationFlags)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get activation flags from storage: %w", err)
|
||||||
|
}
|
||||||
|
if entry == nil {
|
||||||
|
return activated, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var activationFlags map[string]bool
|
||||||
|
if err := entry.DecodeJSON(&activationFlags); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to decode activation flags from storage: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the in-memory flags after loading the latest values from storage
|
||||||
|
f.activationFlags = activationFlags
|
||||||
|
|
||||||
|
for flag, set := range activationFlags {
|
||||||
|
if set {
|
||||||
|
activated = append(activated, flag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return activated, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write is the helper function called by the activation-flags API write endpoint. This stores
|
||||||
|
// the boolean value for the activation-flag feature name into Vault storage across the cluster
|
||||||
|
// and updates the in-memory cache upon success.
|
||||||
|
func (f *FeatureActivationFlags) Write(ctx context.Context, featureName string, activate bool) (err error) {
|
||||||
|
f.activationFlagsLock.Lock()
|
||||||
|
defer f.activationFlagsLock.Unlock()
|
||||||
|
|
||||||
|
if f.storage == nil {
|
||||||
|
return fmt.Errorf("unable to access storage")
|
||||||
|
}
|
||||||
|
|
||||||
|
activationFlags := f.activationFlags
|
||||||
|
|
||||||
|
clonedFlags := maps.Clone(f.activationFlags)
|
||||||
|
clonedFlags[featureName] = activate
|
||||||
|
// The cloned flags are updated but the in-memory state is only updated on success of the storage update.
|
||||||
|
defer func() {
|
||||||
|
if err == nil {
|
||||||
|
activationFlags[featureName] = activate
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
entry, err := logical.StorageEntryJSON(storagePathActivationFlags, clonedFlags)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to marshal object to JSON: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = f.storage.Put(ctx, entry)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to save object in storage: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsActivationFlagEnabled is true if the specified flag is enabled in the core.
|
||||||
|
func (f *FeatureActivationFlags) IsActivationFlagEnabled(featureName string) bool {
|
||||||
|
f.activationFlagsLock.RLock()
|
||||||
|
defer f.activationFlagsLock.RUnlock()
|
||||||
|
|
||||||
|
activated, ok := f.activationFlags[featureName]
|
||||||
|
|
||||||
|
return ok && activated
|
||||||
|
}
|
||||||
@@ -45,6 +45,7 @@ import (
|
|||||||
"github.com/hashicorp/vault/api"
|
"github.com/hashicorp/vault/api"
|
||||||
"github.com/hashicorp/vault/audit"
|
"github.com/hashicorp/vault/audit"
|
||||||
"github.com/hashicorp/vault/command/server"
|
"github.com/hashicorp/vault/command/server"
|
||||||
|
"github.com/hashicorp/vault/helper/activationflags"
|
||||||
"github.com/hashicorp/vault/helper/identity/mfa"
|
"github.com/hashicorp/vault/helper/identity/mfa"
|
||||||
"github.com/hashicorp/vault/helper/locking"
|
"github.com/hashicorp/vault/helper/locking"
|
||||||
"github.com/hashicorp/vault/helper/metricsutil"
|
"github.com/hashicorp/vault/helper/metricsutil"
|
||||||
@@ -739,6 +740,9 @@ type Core struct {
|
|||||||
clusterAddrBridge *raft.ClusterAddrBridge
|
clusterAddrBridge *raft.ClusterAddrBridge
|
||||||
|
|
||||||
censusManager *CensusManager
|
censusManager *CensusManager
|
||||||
|
|
||||||
|
// Activation flags for enterprise features that require a one-time activation
|
||||||
|
FeatureActivationFlags *activationflags.FeatureActivationFlags
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Core) ActiveNodeClockSkewMillis() int64 {
|
func (c *Core) ActiveNodeClockSkewMillis() int64 {
|
||||||
@@ -1448,11 +1452,14 @@ func (c *Core) configureLogicalBackends(backends map[string]logical.Factory, log
|
|||||||
// System
|
// System
|
||||||
logicalBackends[mountTypeSystem] = func(ctx context.Context, config *logical.BackendConfig) (logical.Backend, error) {
|
logicalBackends[mountTypeSystem] = func(ctx context.Context, config *logical.BackendConfig) (logical.Backend, error) {
|
||||||
sysBackendLogger := logger.Named("system")
|
sysBackendLogger := logger.Named("system")
|
||||||
|
|
||||||
c.AddLogger(sysBackendLogger)
|
c.AddLogger(sysBackendLogger)
|
||||||
b := NewSystemBackend(c, sysBackendLogger, config)
|
b := NewSystemBackend(c, sysBackendLogger, config)
|
||||||
|
|
||||||
if err := b.Setup(ctx, config); err != nil {
|
if err := b.Setup(ctx, config); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/hashicorp/go-hclog"
|
"github.com/hashicorp/go-hclog"
|
||||||
|
"github.com/hashicorp/vault/helper/activationflags"
|
||||||
"github.com/hashicorp/vault/helper/namespace"
|
"github.com/hashicorp/vault/helper/namespace"
|
||||||
"github.com/hashicorp/vault/limits"
|
"github.com/hashicorp/vault/limits"
|
||||||
"github.com/hashicorp/vault/sdk/helper/license"
|
"github.com/hashicorp/vault/sdk/helper/license"
|
||||||
@@ -59,6 +60,8 @@ func coreInit(c *Core, conf *CoreConfig) error {
|
|||||||
c.physical = physical.NewStorageEncoding(c.physical)
|
c.physical = physical.NewStorageEncoding(c.physical)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
c.FeatureActivationFlags = activationflags.NewFeatureActivationFlags()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -231,6 +231,7 @@ func NewSystemBackend(core *Core, logger log.Logger, config *logical.BackendConf
|
|||||||
b.Backend.Paths = append(b.Backend.Paths, b.experimentPaths()...)
|
b.Backend.Paths = append(b.Backend.Paths, b.experimentPaths()...)
|
||||||
b.Backend.Paths = append(b.Backend.Paths, b.introspectionPaths()...)
|
b.Backend.Paths = append(b.Backend.Paths, b.introspectionPaths()...)
|
||||||
b.Backend.Paths = append(b.Backend.Paths, b.wellKnownPaths()...)
|
b.Backend.Paths = append(b.Backend.Paths, b.wellKnownPaths()...)
|
||||||
|
b.Backend.Paths = append(b.Backend.Paths, b.activationFlagsPaths()...)
|
||||||
|
|
||||||
if core.rawEnabled {
|
if core.rawEnabled {
|
||||||
b.Backend.Paths = append(b.Backend.Paths, b.rawPaths()...)
|
b.Backend.Paths = append(b.Backend.Paths, b.rawPaths()...)
|
||||||
|
|||||||
140
vault/logical_system_activation_flags.go
Normal file
140
vault/logical_system_activation_flags.go
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
// Copyright (c) HashiCorp, Inc.
|
||||||
|
// SPDX-License-Identifier: BUSL-1.1
|
||||||
|
|
||||||
|
package vault
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"slices"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/hashicorp/vault/sdk/framework"
|
||||||
|
"github.com/hashicorp/vault/sdk/logical"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
paramFeatureName = "feature_name"
|
||||||
|
descFeatureName = "The name of the feature to be activated."
|
||||||
|
summaryList = "Returns the available and activated activation-flagged features."
|
||||||
|
summaryUpdate = "Activate a flagged feature."
|
||||||
|
|
||||||
|
prefixActivationFlags = "activation-flags"
|
||||||
|
verbActivationFlagsActivate = "activate"
|
||||||
|
verbActivationFlagsDeactivate = "deactivate"
|
||||||
|
|
||||||
|
fieldActivated = "activated"
|
||||||
|
fieldUnactivated = "unactivated"
|
||||||
|
|
||||||
|
helpSynopsis = "Returns information about Vault's features that require a one-time activation step."
|
||||||
|
helpDescription = `
|
||||||
|
This path responds to the following HTTP methods.
|
||||||
|
GET /
|
||||||
|
Returns the available and activated activation-flags.
|
||||||
|
|
||||||
|
PUT|POST /<feature-name>/activate
|
||||||
|
Activates the specified feature. Cannot be undone.`
|
||||||
|
)
|
||||||
|
|
||||||
|
// Register CRUD functions dynamically.
|
||||||
|
// These variables should only be mutated during initialization or server construction.
|
||||||
|
// It is unsafe to modify them once the Vault core is running.
|
||||||
|
var (
|
||||||
|
readActivationFlag = func(ctx context.Context, b *SystemBackend, req *logical.Request, fd *framework.FieldData) (*logical.Response, error) {
|
||||||
|
return b.readActivationFlag(ctx, req, fd)
|
||||||
|
}
|
||||||
|
|
||||||
|
writeActivationFlag = func(ctx context.Context, b *SystemBackend, req *logical.Request, fd *framework.FieldData, isActivate bool) (*logical.Response, error) {
|
||||||
|
return b.writeActivationFlagWrite(ctx, req, fd, isActivate)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func (b *SystemBackend) activationFlagsPaths() []*framework.Path {
|
||||||
|
return []*framework.Path{
|
||||||
|
{
|
||||||
|
Pattern: fmt.Sprintf("%s$", prefixActivationFlags),
|
||||||
|
DisplayAttrs: &framework.DisplayAttributes{
|
||||||
|
OperationVerb: "read",
|
||||||
|
OperationSuffix: prefixActivationFlags,
|
||||||
|
},
|
||||||
|
Operations: map[logical.Operation]framework.OperationHandler{
|
||||||
|
logical.ReadOperation: &framework.PathOperation{
|
||||||
|
Callback: b.handleActivationFlagRead,
|
||||||
|
Summary: summaryList,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
HelpSynopsis: helpSynopsis,
|
||||||
|
HelpDescription: helpDescription,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Pattern: fmt.Sprintf("%s/%s/%s", prefixActivationFlags, "activation-test", verbActivationFlagsActivate),
|
||||||
|
DisplayAttrs: &framework.DisplayAttributes{
|
||||||
|
OperationPrefix: prefixActivationFlags,
|
||||||
|
OperationVerb: verbActivationFlagsActivate,
|
||||||
|
},
|
||||||
|
Operations: map[logical.Operation]framework.OperationHandler{
|
||||||
|
logical.UpdateOperation: &framework.PathOperation{
|
||||||
|
Callback: b.handleActivationFlagsActivate,
|
||||||
|
ForwardPerformanceSecondary: true,
|
||||||
|
ForwardPerformanceStandby: true,
|
||||||
|
Summary: summaryUpdate,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
HelpSynopsis: helpSynopsis,
|
||||||
|
HelpDescription: helpDescription,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *SystemBackend) handleActivationFlagRead(ctx context.Context, req *logical.Request, fd *framework.FieldData) (*logical.Response, error) {
|
||||||
|
return readActivationFlag(ctx, b, req, fd)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *SystemBackend) handleActivationFlagsActivate(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
|
||||||
|
return writeActivationFlag(ctx, b, req, data, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *SystemBackend) readActivationFlag(ctx context.Context, req *logical.Request, _ *framework.FieldData) (*logical.Response, error) {
|
||||||
|
activationFlags, err := b.Core.FeatureActivationFlags.Get(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return b.activationFlagsToResponse(activationFlags), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *SystemBackend) writeActivationFlagWrite(ctx context.Context, req *logical.Request, _ *framework.FieldData, isActivate bool) (*logical.Response, error) {
|
||||||
|
// We need to manually parse out the feature_name from the path because we can't use FieldSchema parameters
|
||||||
|
// in the path to make generic endpoints. We need each activation-flag path to be a separate endpoint.
|
||||||
|
// Path starts out as activation-flags/<feature_name>/verb
|
||||||
|
// Removes activation-flags/ from the path
|
||||||
|
trimPrefix := strings.TrimPrefix(req.Path, prefixActivationFlags+"/")
|
||||||
|
// Removes /verb from the path
|
||||||
|
featureName := trimPrefix[:strings.LastIndex(trimPrefix, "/")]
|
||||||
|
|
||||||
|
err := b.Core.FeatureActivationFlags.Write(ctx, featureName, isActivate)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to write new activation flags: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// We read back the value after writing it to storage so that we can try forcing a cache update right away.
|
||||||
|
// If this fails, it's still okay to proceed as the write has been successful and the cache will get updated
|
||||||
|
// at the time of an endpoint getting called. However, we can only return the one feature name we just activated
|
||||||
|
// in the response since the read to retrieve any others did not succeed.
|
||||||
|
activationFlags, err := b.Core.FeatureActivationFlags.Get(ctx)
|
||||||
|
if err != nil {
|
||||||
|
resp := b.activationFlagsToResponse([]string{featureName})
|
||||||
|
return resp, fmt.Errorf("failed to read activation-flags back after write: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return b.activationFlagsToResponse(activationFlags), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *SystemBackend) activationFlagsToResponse(activationFlags []string) *logical.Response {
|
||||||
|
slices.Sort(activationFlags)
|
||||||
|
return &logical.Response{
|
||||||
|
Data: map[string]interface{}{
|
||||||
|
fieldActivated: activationFlags,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
87
vault/logical_system_activation_flags_test.go
Normal file
87
vault/logical_system_activation_flags_test.go
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
// Copyright (c) HashiCorp, Inc.
|
||||||
|
// SPDX-License-Identifier: BUSL-1.1
|
||||||
|
|
||||||
|
package vault
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/hashicorp/vault/helper/namespace"
|
||||||
|
"github.com/hashicorp/vault/sdk/logical"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TestActivationFlags_Read tests the read operation for the activation flags.
|
||||||
|
func TestActivationFlags_Read(t *testing.T) {
|
||||||
|
t.Run("given an initial state then read flags and expect all to be unactivated", func(t *testing.T) {
|
||||||
|
core, _, _ := TestCoreUnsealedWithConfig(t, &CoreConfig{})
|
||||||
|
|
||||||
|
resp, err := core.systemBackend.HandleRequest(
|
||||||
|
context.Background(),
|
||||||
|
&logical.Request{
|
||||||
|
Operation: logical.ReadOperation,
|
||||||
|
Path: prefixActivationFlags,
|
||||||
|
Storage: core.systemBarrierView,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, resp.Data, map[string]interface{}{
|
||||||
|
"activated": []string{},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestActivationFlags_BadFeatureName tests a nonexistent feature name or a missing feature name
|
||||||
|
// in the activation-flags path API call.
|
||||||
|
func TestActivationFlags_BadFeatureName(t *testing.T) {
|
||||||
|
core, _, _ := TestCoreUnsealedWithConfig(t, &CoreConfig{})
|
||||||
|
|
||||||
|
tests := map[string]struct {
|
||||||
|
featureName string
|
||||||
|
}{
|
||||||
|
"if no feature name is provided then expect unsupported path": {
|
||||||
|
featureName: "",
|
||||||
|
},
|
||||||
|
"if an invalid feature name is provided then expect unsupported path": {
|
||||||
|
featureName: "fake-feature",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, tt := range tests {
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
resp, err := core.router.Route(
|
||||||
|
namespace.ContextWithNamespace(context.Background(), namespace.RootNamespace),
|
||||||
|
&logical.Request{
|
||||||
|
Operation: logical.UpdateOperation,
|
||||||
|
Path: fmt.Sprintf("sys/%s/%s/%s", prefixActivationFlags, tt.featureName, verbActivationFlagsActivate),
|
||||||
|
Storage: core.systemBarrierView,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
require.Error(t, err)
|
||||||
|
require.Nil(t, resp)
|
||||||
|
require.Equal(t, err, logical.ErrUnsupportedPath)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestActivationFlags_Write tests the write operations for the activation flags
|
||||||
|
func TestActivationFlags_Write(t *testing.T) {
|
||||||
|
t.Run("given an initial state then read flags and expect all to be unactivated", func(t *testing.T) {
|
||||||
|
core, _, _ := TestCoreUnsealedWithConfig(t, &CoreConfig{})
|
||||||
|
|
||||||
|
_, err := core.systemBackend.HandleRequest(
|
||||||
|
context.Background(),
|
||||||
|
&logical.Request{
|
||||||
|
Operation: logical.UpdateOperation,
|
||||||
|
Path: fmt.Sprintf("%s/%s/%s", prefixActivationFlags, "activation-test", verbActivationFlagsActivate),
|
||||||
|
Storage: core.systemBarrierView,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -31,9 +31,7 @@ var (
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
sysInitialize = func(b *SystemBackend) func(context.Context, *logical.InitializationRequest) error {
|
sysInitialize = ceSysInitialize
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
sysClean = func(b *SystemBackend) func(context.Context) {
|
sysClean = func(b *SystemBackend) func(context.Context) {
|
||||||
return nil
|
return nil
|
||||||
@@ -280,6 +278,16 @@ var (
|
|||||||
checkRaw = func(b *SystemBackend, path string) error { return nil }
|
checkRaw = func(b *SystemBackend, path string) error { return nil }
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func ceSysInitialize(b *SystemBackend) func(context.Context, *logical.InitializationRequest) error {
|
||||||
|
return func(ctx context.Context, req *logical.InitializationRequest) error {
|
||||||
|
err := b.Core.FeatureActivationFlags.Initialize(ctx, b.Core.systemBarrierView)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to initialize activation flags: %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Contains the config for a global plugin reload
|
// Contains the config for a global plugin reload
|
||||||
type pluginReloadRequest struct {
|
type pluginReloadRequest struct {
|
||||||
Type string `json:"type"` // Either 'plugins' or 'mounts'
|
Type string `json:"type"` // Either 'plugins' or 'mounts'
|
||||||
|
|||||||
Reference in New Issue
Block a user