AWS upgrade role entries (#7025)

* upgrade aws roles

* test upgrade aws roles

* Initialize aws credential backend at mount time

* add a TODO

* create end-to-end test for builtin/credential/aws

* fix bug in initializer

* improve comments

* add Initialize() to logical.Backend

* use Initialize() in Core.enableCredentialInternal()

* use InitializeRequest to call Initialize()

* improve unit testing for framework.Backend

* call logical.Backend.Initialize() from all of the places that it needs to be called.

* implement backend.proto changes for logical.Backend.Initialize()

* persist current role storage version when upgrading aws roles

* format comments correctly

* improve comments

* use postUnseal funcs to initialize backends

* simplify test suite

* improve test suite

* simplify logic in aws role upgrade

* simplify aws credential initialization logic

* simplify logic in aws role upgrade

* use the core's activeContext for initialization

* refactor builtin/plugin/Backend

* use a goroutine to upgrade the aws roles

* misc improvements and cleanup

* do not run AWS role upgrade on DR Secondary

* always call logical.Backend.Initialize() when loading a plugin.

* improve comments

* on standbys and DR secondaries we do not want to run any kind of upgrade logic

* fix awsVersion struct

* clarify aws version upgrade

* make the upgrade logic for aws auth more explicit

* aws upgrade is now called from a switch

* fix fallthrough bug

* simplify logic

* simplify logic

* rename things

* introduce currentAwsVersion const to track aws version

* improve comments

* rearrange things once more

* conglomerate things into one function

* stub out aws auth initialize e2e test

* improve aws auth initialize e2e test

* finish aws auth initialize e2e test

* tinker with aws auth initialize e2e test

* tinker with aws auth initialize e2e test

* tinker with aws auth initialize e2e test

* fix typo in test suite

* simplify logic a tad

* rearrange assignment

* Fix a few lifecycle related issues in #7025 (#7075)

* Fix panic when plugin fails to load
This commit is contained in:
Mike Jarmy
2019-07-05 19:55:40 -04:00
committed by Brian Kassouf
parent 8b9e9ea1ec
commit c48159ea3a
21 changed files with 1135 additions and 342 deletions

View File

@@ -35,7 +35,7 @@ type backend struct {
configMutex sync.RWMutex configMutex sync.RWMutex
// Lock to make changes to role entries // Lock to make changes to role entries
roleMutex sync.RWMutex roleMutex sync.Mutex
// Lock to make changes to the blacklist entries // Lock to make changes to the blacklist entries
blacklistMutex sync.RWMutex blacklistMutex sync.RWMutex
@@ -81,6 +81,10 @@ type backend struct {
roleCache *cache.Cache roleCache *cache.Cache
resolveArnToUniqueIDFunc func(context.Context, logical.Storage, string) (string, error) resolveArnToUniqueIDFunc func(context.Context, logical.Storage, string) (string, error)
// upgradeCancelFunc is used to cancel the context used in the upgrade
// function
upgradeCancelFunc context.CancelFunc
} }
func Backend(conf *logical.BackendConfig) (*backend, error) { func Backend(conf *logical.BackendConfig) (*backend, error) {
@@ -134,8 +138,10 @@ func Backend(conf *logical.BackendConfig) (*backend, error) {
pathIdentityWhitelist(b), pathIdentityWhitelist(b),
pathTidyIdentityWhitelist(b), pathTidyIdentityWhitelist(b),
}, },
Invalidate: b.invalidate, Invalidate: b.invalidate,
BackendType: logical.TypeCredential, InitializeFunc: b.initialize,
BackendType: logical.TypeCredential,
Clean: b.cleanup,
} }
return b, nil return b, nil
@@ -205,6 +211,12 @@ func (b *backend) periodicFunc(ctx context.Context, req *logical.Request) error
return nil return nil
} }
func (b *backend) cleanup(ctx context.Context) {
if b.upgradeCancelFunc != nil {
b.upgradeCancelFunc()
}
}
func (b *backend) invalidate(ctx context.Context, key string) { func (b *backend) invalidate(ctx context.Context, key string) {
switch { switch {
case key == "config/client": case key == "config/client":

View File

@@ -0,0 +1,133 @@
package awsauth
import (
"context"
"testing"
"time"
hclog "github.com/hashicorp/go-hclog"
"github.com/hashicorp/vault/api"
vaulthttp "github.com/hashicorp/vault/http"
"github.com/hashicorp/vault/sdk/helper/logging"
"github.com/hashicorp/vault/sdk/logical"
"github.com/hashicorp/vault/vault"
)
func TestBackend_E2E_Initialize(t *testing.T) {
ctx := context.Background()
// Set up the cluster. This will trigger an Initialize(); we sleep briefly
// awaiting its completion.
cluster := setupAwsTestCluster(t, ctx)
defer cluster.Cleanup()
time.Sleep(time.Second)
core := cluster.Cores[0]
// Fetch the aws auth's path in storage. This is a uuid that is different
// every time we run the test
authUuids, err := core.UnderlyingStorage.List(ctx, "auth/")
if err != nil {
t.Fatal(err)
}
if len(authUuids) != 1 {
t.Fatalf("expected exactly one auth path")
}
awsPath := "auth/" + authUuids[0]
// Make sure that the upgrade happened, by fishing the 'config/version'
// entry out of storage. We can't use core.Client.Logical().Read() to do
// this, because 'config/version' hasn't been exposed as a path.
// TODO: should we expose 'config/version' as a path?
version, err := core.UnderlyingStorage.Get(ctx, awsPath+"config/version")
if err != nil {
t.Fatal(err)
}
if version == nil {
t.Fatalf("no config found")
}
// Nuke the version, so we can pretend that Initialize() has never been run
if err := core.UnderlyingStorage.Delete(ctx, awsPath+"config/version"); err != nil {
t.Fatal(err)
}
version, err = core.UnderlyingStorage.Get(ctx, awsPath+"config/version")
if err != nil {
t.Fatal(err)
}
if version != nil {
t.Fatalf("version found")
}
// Create a role
data := map[string]interface{}{
"auth_type": "ec2",
"policies": "default",
"bound_subnet_id": "subnet-abcdef"}
if _, err := core.Client.Logical().Write("auth/aws/role/test-role", data); err != nil {
t.Fatal(err)
}
role, err := core.Client.Logical().Read("auth/aws/role/test-role")
if err != nil {
t.Fatal(err)
}
if role == nil {
t.Fatalf("no role found")
}
// There should _still_ be no config version
version, err = core.UnderlyingStorage.Get(ctx, awsPath+"config/version")
if err != nil {
t.Fatal(err)
}
if version != nil {
t.Fatalf("version found")
}
// Seal, and then Unseal. This will once again trigger an Initialize(),
// only this time there will be a role present during the upgrade.
core.Seal(t)
cluster.UnsealCores(t)
time.Sleep(time.Second)
// Now the config version should be there again
version, err = core.UnderlyingStorage.Get(ctx, awsPath+"config/version")
if err != nil {
t.Fatal(err)
}
if version == nil {
t.Fatalf("no version found")
}
}
func setupAwsTestCluster(t *testing.T, ctx context.Context) *vault.TestCluster {
// create a cluster with the aws auth backend built-in
logger := logging.NewVaultLogger(hclog.Trace)
coreConfig := &vault.CoreConfig{
Logger: logger,
CredentialBackends: map[string]logical.Factory{
"aws": Factory,
},
}
cluster := vault.NewTestCluster(t, coreConfig, &vault.TestClusterOptions{
NumCores: 1,
HandlerFunc: vaulthttp.Handler,
})
cluster.Start()
if len(cluster.Cores) != 1 {
t.Fatalf("expected exactly one core")
}
core := cluster.Cores[0]
vault.TestWaitActive(t, core.Core)
// load the auth plugin
if err := core.Client.Sys().EnableAuthWithOptions("aws", &api.EnableAuthOptions{
Type: "aws",
}); err != nil {
t.Fatal(err)
}
return cluster
}

View File

@@ -319,6 +319,119 @@ func (b *backend) setRole(ctx context.Context, s logical.Storage, roleName strin
return nil return nil
} }
// initialize is used to initialize the AWS roles
func (b *backend) initialize(ctx context.Context, req *logical.InitializationRequest) error {
// on standbys and DR secondaries we do not want to run any kind of upgrade logic
if b.System().ReplicationState().HasState(consts.ReplicationPerformanceStandby | consts.ReplicationDRSecondary) {
return nil
}
// Initialize only if we are either:
// (1) A local mount.
// (2) Are _NOT_ a replicated performance secondary
if b.System().LocalMount() || !b.System().ReplicationState().HasState(consts.ReplicationPerformanceSecondary) {
s := req.Storage
logger := b.Logger().Named("initialize")
logger.Debug("starting initialization")
var upgradeCtx context.Context
upgradeCtx, b.upgradeCancelFunc = context.WithCancel(context.Background())
go func() {
// The vault will become unsealed while this goroutine is running,
// so we could see some role requests block until the lock is
// released. However we'd rather see those requests block (and
// potentially start timing out) than allow a non-upgraded role to
// be fetched.
b.roleMutex.Lock()
defer b.roleMutex.Unlock()
upgraded, err := b.upgrade(upgradeCtx, s)
if err != nil {
logger.Error("error running initialization", "error", err)
return
}
if upgraded {
logger.Info("an upgrade was performed during initialization")
}
}()
}
return nil
}
// awsVersion stores info about the the latest aws version that we have
// upgraded to.
type awsVersion struct {
Version int `json:"version"`
}
// currentAwsVersion stores the latest version that we have upgraded to.
// Note that this is tracked independently from currentRoleStorageVersion.
const currentAwsVersion = 1
// upgrade does an upgrade, if necessary
func (b *backend) upgrade(ctx context.Context, s logical.Storage) (bool, error) {
entry, err := s.Get(ctx, "config/version")
if err != nil {
return false, err
}
var version awsVersion
if entry != nil {
err = entry.DecodeJSON(&version)
if err != nil {
return false, err
}
}
upgraded := version.Version < currentAwsVersion
switch version.Version {
case 0:
// Read all the role names.
roleNames, err := s.List(ctx, "role/")
if err != nil {
return false, err
}
// Upgrade the roles as necessary.
for _, roleName := range roleNames {
// make sure the context hasn't been canceled
if ctx.Err() != nil {
return false, err
}
_, err := b.roleInternal(ctx, s, roleName)
if err != nil {
return false, err
}
}
fallthrough
case currentAwsVersion:
version.Version = currentAwsVersion
default:
return false, fmt.Errorf("unrecognized role version: %d", version.Version)
}
// save the current version
if upgraded {
entry, err = logical.StorageEntryJSON("config/version", &version)
if err != nil {
return false, err
}
err = s.Put(ctx, entry)
if err != nil {
return false, err
}
}
return upgraded, nil
}
// If needed, updates the role entry and returns a bool indicating if it was updated // If needed, updates the role entry and returns a bool indicating if it was updated
// (and thus needs to be persisted) // (and thus needs to be persisted)
func (b *backend) upgradeRole(ctx context.Context, s logical.Storage, roleEntry *awsRoleEntry) (bool, error) { func (b *backend) upgradeRole(ctx context.Context, s logical.Storage, roleEntry *awsRoleEntry) (bool, error) {

View File

@@ -809,6 +809,183 @@ func TestRoleEntryUpgradeV(t *testing.T) {
} }
} }
func TestRoleInitialize(t *testing.T) {
config := logical.TestBackendConfig()
storage := &logical.InmemStorage{}
config.StorageView = storage
b, err := Backend(config)
if err != nil {
t.Fatal(err)
}
ctx := context.Background()
err = b.Setup(ctx, config)
if err != nil {
t.Fatal(err)
}
// create some role entries, some of which will need to be upgraded
type testData struct {
name string
entry *awsRoleEntry
}
before := []testData{
{
name: "role1",
entry: &awsRoleEntry{
BoundIamRoleARNs: []string{"arn:aws:iam::000000000001:role/my_role_prefix"},
BoundIamInstanceProfileARNs: []string{"arn:aws:iam::000000000001:instance-profile/my_profile-prefix"},
Version: 1,
},
},
{
name: "role2",
entry: &awsRoleEntry{
BoundIamRoleARNs: []string{"arn:aws:iam::000000000002:role/my_role_prefix"},
BoundIamInstanceProfileARNs: []string{"arn:aws:iam::000000000002:instance-profile/my_profile-prefix"},
Version: 2,
},
},
{
name: "role3",
entry: &awsRoleEntry{
BoundIamRoleARNs: []string{"arn:aws:iam::000000000003:role/my_role_prefix"},
BoundIamInstanceProfileARNs: []string{"arn:aws:iam::000000000003:instance-profile/my_profile-prefix"},
Version: currentRoleStorageVersion,
},
},
}
// put the entries in storage
for _, role := range before {
err = b.setRole(ctx, storage, role.name, role.entry)
if err != nil {
t.Fatal(err)
}
}
// upgrade all the entries
upgraded, err := b.upgrade(ctx, storage)
if err != nil {
t.Fatal(err)
}
if !upgraded {
t.Fatalf("expected upgrade")
}
// read the entries from storage
after := make([]testData, 0)
names, err := storage.List(ctx, "role/")
if err != nil {
t.Fatal(err)
}
for _, name := range names {
entry, err := b.role(ctx, storage, name)
if err != nil {
t.Fatal(err)
}
after = append(after, testData{name: name, entry: entry})
}
// make sure each entry is at the current version
expected := []testData{
{
name: "role1",
entry: &awsRoleEntry{
BoundIamRoleARNs: []string{"arn:aws:iam::000000000001:role/my_role_prefix"},
BoundIamInstanceProfileARNs: []string{"arn:aws:iam::000000000001:instance-profile/my_profile-prefix"},
Version: currentRoleStorageVersion,
},
},
{
name: "role2",
entry: &awsRoleEntry{
BoundIamRoleARNs: []string{"arn:aws:iam::000000000002:role/my_role_prefix"},
BoundIamInstanceProfileARNs: []string{"arn:aws:iam::000000000002:instance-profile/my_profile-prefix"},
Version: currentRoleStorageVersion,
},
},
{
name: "role3",
entry: &awsRoleEntry{
BoundIamRoleARNs: []string{"arn:aws:iam::000000000003:role/my_role_prefix"},
BoundIamInstanceProfileARNs: []string{"arn:aws:iam::000000000003:instance-profile/my_profile-prefix"},
Version: currentRoleStorageVersion,
},
},
}
if diff := deep.Equal(expected, after); diff != nil {
t.Fatal(diff)
}
// run it again -- nothing will happen
upgraded, err = b.upgrade(ctx, storage)
if err != nil {
t.Fatal(err)
}
if upgraded {
t.Fatalf("expected no upgrade")
}
// make sure saved role version is correct
entry, err := storage.Get(ctx, "config/version")
if err != nil {
t.Fatal(err)
}
var version awsVersion
err = entry.DecodeJSON(&version)
if err != nil {
t.Fatal(err)
}
if version.Version != currentAwsVersion {
t.Fatalf("expected version %d, got %d", currentAwsVersion, version.Version)
}
// stomp on the saved version
version.Version = 0
e2, err := logical.StorageEntryJSON("config/version", version)
if err != nil {
t.Fatal(err)
}
err = storage.Put(ctx, e2)
if err != nil {
t.Fatal(err)
}
// run it again -- now an upgrade will happen
upgraded, err = b.upgrade(ctx, storage)
if err != nil {
t.Fatal(err)
}
if !upgraded {
t.Fatalf("expected upgrade")
}
}
func TestAwsVersion(t *testing.T) {
before := awsVersion{
Version: 42,
}
entry, err := logical.StorageEntryJSON("config/version", &before)
if err != nil {
t.Fatal(err)
}
var after awsVersion
err = entry.DecodeJSON(&after)
if err != nil {
t.Fatal(err)
}
if diff := deep.Equal(before, after); diff != nil {
t.Fatal(diff)
}
}
func resolveArnToFakeUniqueId(ctx context.Context, s logical.Storage, arn string) (string, error) { func resolveArnToFakeUniqueId(ctx context.Context, s logical.Storage, arn string) (string, error) {
return "FakeUniqueId1", nil return "FakeUniqueId1", nil
} }

View File

@@ -91,13 +91,8 @@ type PluginBackend struct {
loaded bool loaded bool
} }
func (b *PluginBackend) reloadBackend(ctx context.Context) error {
b.Logger().Debug("reloading plugin backend", "plugin", b.config.Config["plugin_name"])
return b.startBackend(ctx)
}
// startBackend starts a plugin backend // startBackend starts a plugin backend
func (b *PluginBackend) startBackend(ctx context.Context) error { func (b *PluginBackend) startBackend(ctx context.Context, storage logical.Storage) error {
pluginName := b.config.Config["plugin_name"] pluginName := b.config.Config["plugin_name"]
pluginType, err := consts.ParsePluginType(b.config.Config["plugin_type"]) pluginType, err := consts.ParsePluginType(b.config.Config["plugin_type"])
if err != nil { if err != nil {
@@ -134,11 +129,14 @@ func (b *PluginBackend) startBackend(ctx context.Context) error {
b.Backend = nb b.Backend = nb
b.loaded = true b.loaded = true
return nil // call Initialize() explicitly here.
return b.Backend.Initialize(ctx, &logical.InitializationRequest{
Storage: storage,
})
} }
// HandleRequest is a thin wrapper implementation of HandleRequest that includes automatic plugin reload. // lazyLoad lazy-loads the backend before running a method
func (b *PluginBackend) HandleRequest(ctx context.Context, req *logical.Request) (*logical.Response, error) { func (b *PluginBackend) lazyLoadBackend(ctx context.Context, storage logical.Storage, methodWrapper func() error) error {
b.RLock() b.RLock()
canary := b.canary canary := b.canary
@@ -149,17 +147,19 @@ func (b *PluginBackend) HandleRequest(ctx context.Context, req *logical.Request)
b.Lock() b.Lock()
// Check once more after lock swap // Check once more after lock swap
if !b.loaded { if !b.loaded {
err := b.startBackend(ctx) err := b.startBackend(ctx, storage)
if err != nil { if err != nil {
b.Unlock() b.Unlock()
return nil, err return err
} }
} }
b.Unlock() b.Unlock()
b.RLock() b.RLock()
} }
resp, err := b.Backend.HandleRequest(ctx, req)
err := methodWrapper()
b.RUnlock() b.RUnlock()
// Need to compare string value for case were err comes from plugin RPC // Need to compare string value for case were err comes from plugin RPC
// and is returned as plugin.BasicError type. // and is returned as plugin.BasicError type.
if err != nil && if err != nil &&
@@ -167,73 +167,60 @@ func (b *PluginBackend) HandleRequest(ctx context.Context, req *logical.Request)
// Reload plugin if it's an rpc.ErrShutdown // Reload plugin if it's an rpc.ErrShutdown
b.Lock() b.Lock()
if b.canary == canary { if b.canary == canary {
err := b.reloadBackend(ctx) b.Logger().Debug("reloading plugin backend", "plugin", b.config.Config["plugin_name"])
err := b.startBackend(ctx, storage)
if err != nil { if err != nil {
b.Unlock() b.Unlock()
return nil, err return err
} }
b.canary, err = uuid.GenerateUUID() b.canary, err = uuid.GenerateUUID()
if err != nil { if err != nil {
b.Unlock() b.Unlock()
return nil, err return err
} }
} }
b.Unlock() b.Unlock()
// Try request once more // Try once more
b.RLock() b.RLock()
defer b.RUnlock() defer b.RUnlock()
return b.Backend.HandleRequest(ctx, req) return methodWrapper()
} }
return resp, err return err
} }
// HandleExistenceCheck is a thin wrapper implementation of HandleRequest that includes automatic plugin reload. // HandleRequest is a thin wrapper implementation of HandleRequest that includes automatic plugin reload.
func (b *PluginBackend) HandleExistenceCheck(ctx context.Context, req *logical.Request) (bool, bool, error) { func (b *PluginBackend) HandleRequest(ctx context.Context, req *logical.Request) (resp *logical.Response, err error) {
b.RLock()
canary := b.canary
// Lazy-load backend err = b.lazyLoadBackend(ctx, req.Storage, func() error {
if !b.loaded { var merr error
// Upgrade lock resp, merr = b.Backend.HandleRequest(ctx, req)
b.RUnlock() return merr
b.Lock() })
// Check once more after lock swap
if !b.loaded {
err := b.startBackend(ctx)
if err != nil {
b.Unlock()
return false, false, err
}
}
b.Unlock()
b.RLock()
}
checkFound, exists, err := b.Backend.HandleExistenceCheck(ctx, req) return
b.RUnlock() }
if err != nil &&
(err.Error() == rpc.ErrShutdown.Error() || err == bplugin.ErrPluginShutdown) { // HandleExistenceCheck is a thin wrapper implementation of HandleExistenceCheck that includes automatic plugin reload.
// Reload plugin if it's an rpc.ErrShutdown func (b *PluginBackend) HandleExistenceCheck(ctx context.Context, req *logical.Request) (checkFound bool, exists bool, err error) {
b.Lock()
if b.canary == canary { err = b.lazyLoadBackend(ctx, req.Storage, func() error {
err := b.reloadBackend(ctx) var merr error
if err != nil { checkFound, exists, merr = b.Backend.HandleExistenceCheck(ctx, req)
b.Unlock() return merr
return false, false, err })
}
b.canary, err = uuid.GenerateUUID() return
if err != nil { }
b.Unlock()
return false, false, err // Initialize is a thin wrapper implementation of Initialize that includes automatic plugin reload.
} func (b *PluginBackend) Initialize(ctx context.Context, req *logical.InitializationRequest) error {
}
b.Unlock() // This method is only ever called just after mounting, so we know that the
// call to lazyLoadBackend() will call startBackend(). Since
// Try request once more // startBackend() calls Initialize() on the underlying logical.Backend, the
b.RLock() // method wrapper that we pass in here is a no-op
defer b.RUnlock() return b.lazyLoadBackend(ctx, req.Storage, func() error {
return b.Backend.HandleExistenceCheck(ctx, req) return nil
} })
return checkFound, exists, err
} }

View File

@@ -49,6 +49,10 @@ type Backend struct {
// and ease specifying callbacks for revocation, renewal, etc. // and ease specifying callbacks for revocation, renewal, etc.
Secrets []*Secret Secrets []*Secret
// InitializeFunc is the callback, which if set, will be invoked via
// Initialize() just after a plugin has been mounted.
InitializeFunc InitializeFunc
// PeriodicFunc is the callback, which if set, will be invoked when the // PeriodicFunc is the callback, which if set, will be invoked when the
// periodic timer of RollbackManager ticks. This can be used by // periodic timer of RollbackManager ticks. This can be used by
// backends to do anything it wishes to do periodically. // backends to do anything it wishes to do periodically.
@@ -108,6 +112,18 @@ type CleanupFunc func(context.Context)
// InvalidateFunc is the callback for backend key invalidation. // InvalidateFunc is the callback for backend key invalidation.
type InvalidateFunc func(context.Context, string) type InvalidateFunc func(context.Context, string)
// InitializeFunc is the callback, which if set, will be invoked via
// Initialize() just after a plugin has been mounted.
type InitializeFunc func(context.Context, *logical.InitializationRequest) error
// Initialize is the logical.Backend implementation.
func (b *Backend) Initialize(ctx context.Context, req *logical.InitializationRequest) error {
if b.InitializeFunc != nil {
return b.InitializeFunc(ctx, req)
}
return nil
}
// HandleExistenceCheck is the logical.Backend implementation. // HandleExistenceCheck is the logical.Backend implementation.
func (b *Backend) HandleExistenceCheck(ctx context.Context, req *logical.Request) (checkFound bool, exists bool, err error) { func (b *Backend) HandleExistenceCheck(ctx context.Context, req *logical.Request) (checkFound bool, exists bool, err error) {
b.once.Do(b.init) b.once.Do(b.init)

View File

@@ -642,3 +642,18 @@ func TestFieldSchemaDefaultOrZero(t *testing.T) {
} }
} }
} }
func TestInitializeBackend(t *testing.T) {
var inited bool
backend := &Backend{InitializeFunc: func(context.Context, *logical.InitializationRequest) error {
inited = true
return nil
}}
backend.Initialize(nil, &logical.InitializationRequest{Storage: nil})
if !inited {
t.Fatal("backend should be open")
}
}

View File

@@ -38,6 +38,10 @@ func (b BackendType) String() string {
// allows for a "procfs" like interaction, as internal state can be exposed by // allows for a "procfs" like interaction, as internal state can be exposed by
// acting like a logical backend and being mounted. // acting like a logical backend and being mounted.
type Backend interface { type Backend interface {
// Initialize is used to initialize a plugin after it has been mounted.
Initialize(context.Context, *InitializationRequest) error
// HandleRequest is used to handle a request and generate a response. // HandleRequest is used to handle a request and generate a response.
// The backends must check the operation type and handle appropriately. // The backends must check the operation type and handle appropriately.
HandleRequest(context.Context, *Request) (*Response, error) HandleRequest(context.Context, *Request) (*Response, error)

View File

@@ -303,3 +303,11 @@ const (
) )
type MFACreds map[string][]string type MFACreds map[string][]string
// InitializationRequest stores the parameters and context of an Initialize()
// call being made to a logical.Backend.
type InitializationRequest struct {
// Storage can be used to durably store and retrieve state.
Storage Storage
}

View File

@@ -7,6 +7,8 @@ import (
"sync/atomic" "sync/atomic"
"google.golang.org/grpc" "google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
log "github.com/hashicorp/go-hclog" log "github.com/hashicorp/go-hclog"
plugin "github.com/hashicorp/go-plugin" plugin "github.com/hashicorp/go-plugin"
@@ -44,6 +46,38 @@ type backendGRPCPluginClient struct {
doneCtx context.Context doneCtx context.Context
} }
func (b *backendGRPCPluginClient) Initialize(ctx context.Context, _ *logical.InitializationRequest) error {
if b.metadataMode {
return nil
}
ctx, cancel := context.WithCancel(ctx)
quitCh := pluginutil.CtxCancelIfCanceled(cancel, b.doneCtx)
defer close(quitCh)
defer cancel()
reply, err := b.client.Initialize(ctx, &pb.InitializeArgs{}, largeMsgGRPCCallOpts...)
if err != nil {
if b.doneCtx.Err() != nil {
return ErrPluginShutdown
}
// If the plugin doesn't have Initialize implemented we should not fail
// the initalize call; otherwise this could halt startup of vault.
grpcStatus, ok := status.FromError(err)
if ok && grpcStatus.Code() == codes.Unimplemented {
return nil
}
return err
}
if reply.Err != nil {
return pb.ProtoErrToErr(reply.Err)
}
return nil
}
func (b *backendGRPCPluginClient) HandleRequest(ctx context.Context, req *logical.Request) (*logical.Response, error) { func (b *backendGRPCPluginClient) HandleRequest(ctx context.Context, req *logical.Request) (*logical.Response, error) {
if b.metadataMode { if b.metadataMode {
return nil, ErrClientInMetadataMode return nil, ErrClientInMetadataMode

View File

@@ -84,6 +84,22 @@ func (b *backendGRPCPluginServer) HandleRequest(ctx context.Context, args *pb.Ha
}, nil }, nil
} }
func (b *backendGRPCPluginServer) Initialize(ctx context.Context, _ *pb.InitializeArgs) (*pb.InitializeReply, error) {
if pluginutil.InMetadataMode() {
return &pb.InitializeReply{}, ErrServerInMetadataMode
}
req := &logical.InitializationRequest{
Storage: newGRPCStorageClient(b.brokeredClient),
}
respErr := b.backend.Initialize(ctx, req)
return &pb.InitializeReply{
Err: pb.ErrToProtoErr(respErr),
}, nil
}
func (b *backendGRPCPluginServer) SpecialPaths(ctx context.Context, args *pb.Empty) (*pb.SpecialPathsReply, error) { func (b *backendGRPCPluginServer) SpecialPaths(ctx context.Context, args *pb.Empty) (*pb.SpecialPathsReply, error) {
paths := b.backend.SpecialPaths() paths := b.backend.SpecialPaths()
if paths == nil { if paths == nil {

View File

@@ -137,6 +137,16 @@ func TestGRPCBackendPlugin_Setup(t *testing.T) {
defer cleanup() defer cleanup()
} }
func TestGRPCBackendPlugin_Initialize(t *testing.T) {
b, cleanup := testGRPCBackend(t)
defer cleanup()
err := b.Initialize(context.Background(), &logical.InitializationRequest{})
if err != nil {
t.Fatal(err)
}
}
func testGRPCBackend(t *testing.T) (logical.Backend, func()) { func testGRPCBackend(t *testing.T) (logical.Backend, func()) {
// Create a mock provider // Create a mock provider
pluginMap := map[string]gplugin.Plugin{ pluginMap := map[string]gplugin.Plugin{

View File

@@ -19,6 +19,15 @@ type backendTracingMiddleware struct {
// Validate the backendTracingMiddle object satisfies the backend interface // Validate the backendTracingMiddle object satisfies the backend interface
var _ logical.Backend = &backendTracingMiddleware{} var _ logical.Backend = &backendTracingMiddleware{}
func (b *backendTracingMiddleware) Initialize(ctx context.Context, req *logical.InitializationRequest) (err error) {
defer func(then time.Time) {
b.logger.Trace("initialize", "status", "finished", "err", err, "took", time.Since(then))
}(time.Now())
b.logger.Trace("initialize", "status", "started")
return b.next.Initialize(ctx, req)
}
func (b *backendTracingMiddleware) HandleRequest(ctx context.Context, req *logical.Request) (resp *logical.Response, err error) { func (b *backendTracingMiddleware) HandleRequest(ctx context.Context, req *logical.Request) (resp *logical.Response, err error) {
defer func(then time.Time) { defer func(then time.Time) {
b.logger.Trace("handle request", "path", req.Path, "status", "finished", "err", err, "took", time.Since(then)) b.logger.Trace("handle request", "path", req.Path, "status", "finished", "err", err, "took", time.Since(then))

View File

@@ -10,8 +10,6 @@ import (
timestamp "github.com/golang/protobuf/ptypes/timestamp" timestamp "github.com/golang/protobuf/ptypes/timestamp"
logical "github.com/hashicorp/vault/sdk/logical" logical "github.com/hashicorp/vault/sdk/logical"
grpc "google.golang.org/grpc" grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
math "math" math "math"
) )
@@ -1372,6 +1370,78 @@ func (m *HandleRequestReply) GetErr() *ProtoError {
return nil return nil
} }
// InitializeArgs is the args for Initialize method.
type InitializeArgs struct {
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *InitializeArgs) Reset() { *m = InitializeArgs{} }
func (m *InitializeArgs) String() string { return proto.CompactTextString(m) }
func (*InitializeArgs) ProtoMessage() {}
func (*InitializeArgs) Descriptor() ([]byte, []int) {
return fileDescriptor_4dbf1dfe0c11846b, []int{14}
}
func (m *InitializeArgs) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_InitializeArgs.Unmarshal(m, b)
}
func (m *InitializeArgs) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_InitializeArgs.Marshal(b, m, deterministic)
}
func (m *InitializeArgs) XXX_Merge(src proto.Message) {
xxx_messageInfo_InitializeArgs.Merge(m, src)
}
func (m *InitializeArgs) XXX_Size() int {
return xxx_messageInfo_InitializeArgs.Size(m)
}
func (m *InitializeArgs) XXX_DiscardUnknown() {
xxx_messageInfo_InitializeArgs.DiscardUnknown(m)
}
var xxx_messageInfo_InitializeArgs proto.InternalMessageInfo
// InitializeReply is the reply for Initialize method.
type InitializeReply struct {
Err *ProtoError `sentinel:"" protobuf:"bytes,1,opt,name=err,proto3" json:"err,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *InitializeReply) Reset() { *m = InitializeReply{} }
func (m *InitializeReply) String() string { return proto.CompactTextString(m) }
func (*InitializeReply) ProtoMessage() {}
func (*InitializeReply) Descriptor() ([]byte, []int) {
return fileDescriptor_4dbf1dfe0c11846b, []int{15}
}
func (m *InitializeReply) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_InitializeReply.Unmarshal(m, b)
}
func (m *InitializeReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_InitializeReply.Marshal(b, m, deterministic)
}
func (m *InitializeReply) XXX_Merge(src proto.Message) {
xxx_messageInfo_InitializeReply.Merge(m, src)
}
func (m *InitializeReply) XXX_Size() int {
return xxx_messageInfo_InitializeReply.Size(m)
}
func (m *InitializeReply) XXX_DiscardUnknown() {
xxx_messageInfo_InitializeReply.DiscardUnknown(m)
}
var xxx_messageInfo_InitializeReply proto.InternalMessageInfo
func (m *InitializeReply) GetErr() *ProtoError {
if m != nil {
return m.Err
}
return nil
}
// SpecialPathsReply is the reply for SpecialPaths method. // SpecialPathsReply is the reply for SpecialPaths method.
type SpecialPathsReply struct { type SpecialPathsReply struct {
Paths *Paths `sentinel:"" protobuf:"bytes,1,opt,name=paths,proto3" json:"paths,omitempty"` Paths *Paths `sentinel:"" protobuf:"bytes,1,opt,name=paths,proto3" json:"paths,omitempty"`
@@ -1384,7 +1454,7 @@ func (m *SpecialPathsReply) Reset() { *m = SpecialPathsReply{} }
func (m *SpecialPathsReply) String() string { return proto.CompactTextString(m) } func (m *SpecialPathsReply) String() string { return proto.CompactTextString(m) }
func (*SpecialPathsReply) ProtoMessage() {} func (*SpecialPathsReply) ProtoMessage() {}
func (*SpecialPathsReply) Descriptor() ([]byte, []int) { func (*SpecialPathsReply) Descriptor() ([]byte, []int) {
return fileDescriptor_4dbf1dfe0c11846b, []int{14} return fileDescriptor_4dbf1dfe0c11846b, []int{16}
} }
func (m *SpecialPathsReply) XXX_Unmarshal(b []byte) error { func (m *SpecialPathsReply) XXX_Unmarshal(b []byte) error {
@@ -1425,7 +1495,7 @@ func (m *HandleExistenceCheckArgs) Reset() { *m = HandleExistenceCheckAr
func (m *HandleExistenceCheckArgs) String() string { return proto.CompactTextString(m) } func (m *HandleExistenceCheckArgs) String() string { return proto.CompactTextString(m) }
func (*HandleExistenceCheckArgs) ProtoMessage() {} func (*HandleExistenceCheckArgs) ProtoMessage() {}
func (*HandleExistenceCheckArgs) Descriptor() ([]byte, []int) { func (*HandleExistenceCheckArgs) Descriptor() ([]byte, []int) {
return fileDescriptor_4dbf1dfe0c11846b, []int{15} return fileDescriptor_4dbf1dfe0c11846b, []int{17}
} }
func (m *HandleExistenceCheckArgs) XXX_Unmarshal(b []byte) error { func (m *HandleExistenceCheckArgs) XXX_Unmarshal(b []byte) error {
@@ -1474,7 +1544,7 @@ func (m *HandleExistenceCheckReply) Reset() { *m = HandleExistenceCheckR
func (m *HandleExistenceCheckReply) String() string { return proto.CompactTextString(m) } func (m *HandleExistenceCheckReply) String() string { return proto.CompactTextString(m) }
func (*HandleExistenceCheckReply) ProtoMessage() {} func (*HandleExistenceCheckReply) ProtoMessage() {}
func (*HandleExistenceCheckReply) Descriptor() ([]byte, []int) { func (*HandleExistenceCheckReply) Descriptor() ([]byte, []int) {
return fileDescriptor_4dbf1dfe0c11846b, []int{16} return fileDescriptor_4dbf1dfe0c11846b, []int{18}
} }
func (m *HandleExistenceCheckReply) XXX_Unmarshal(b []byte) error { func (m *HandleExistenceCheckReply) XXX_Unmarshal(b []byte) error {
@@ -1530,7 +1600,7 @@ func (m *SetupArgs) Reset() { *m = SetupArgs{} }
func (m *SetupArgs) String() string { return proto.CompactTextString(m) } func (m *SetupArgs) String() string { return proto.CompactTextString(m) }
func (*SetupArgs) ProtoMessage() {} func (*SetupArgs) ProtoMessage() {}
func (*SetupArgs) Descriptor() ([]byte, []int) { func (*SetupArgs) Descriptor() ([]byte, []int) {
return fileDescriptor_4dbf1dfe0c11846b, []int{17} return fileDescriptor_4dbf1dfe0c11846b, []int{19}
} }
func (m *SetupArgs) XXX_Unmarshal(b []byte) error { func (m *SetupArgs) XXX_Unmarshal(b []byte) error {
@@ -1584,7 +1654,7 @@ func (m *SetupReply) Reset() { *m = SetupReply{} }
func (m *SetupReply) String() string { return proto.CompactTextString(m) } func (m *SetupReply) String() string { return proto.CompactTextString(m) }
func (*SetupReply) ProtoMessage() {} func (*SetupReply) ProtoMessage() {}
func (*SetupReply) Descriptor() ([]byte, []int) { func (*SetupReply) Descriptor() ([]byte, []int) {
return fileDescriptor_4dbf1dfe0c11846b, []int{18} return fileDescriptor_4dbf1dfe0c11846b, []int{20}
} }
func (m *SetupReply) XXX_Unmarshal(b []byte) error { func (m *SetupReply) XXX_Unmarshal(b []byte) error {
@@ -1624,7 +1694,7 @@ func (m *TypeReply) Reset() { *m = TypeReply{} }
func (m *TypeReply) String() string { return proto.CompactTextString(m) } func (m *TypeReply) String() string { return proto.CompactTextString(m) }
func (*TypeReply) ProtoMessage() {} func (*TypeReply) ProtoMessage() {}
func (*TypeReply) Descriptor() ([]byte, []int) { func (*TypeReply) Descriptor() ([]byte, []int) {
return fileDescriptor_4dbf1dfe0c11846b, []int{19} return fileDescriptor_4dbf1dfe0c11846b, []int{21}
} }
func (m *TypeReply) XXX_Unmarshal(b []byte) error { func (m *TypeReply) XXX_Unmarshal(b []byte) error {
@@ -1663,7 +1733,7 @@ func (m *InvalidateKeyArgs) Reset() { *m = InvalidateKeyArgs{} }
func (m *InvalidateKeyArgs) String() string { return proto.CompactTextString(m) } func (m *InvalidateKeyArgs) String() string { return proto.CompactTextString(m) }
func (*InvalidateKeyArgs) ProtoMessage() {} func (*InvalidateKeyArgs) ProtoMessage() {}
func (*InvalidateKeyArgs) Descriptor() ([]byte, []int) { func (*InvalidateKeyArgs) Descriptor() ([]byte, []int) {
return fileDescriptor_4dbf1dfe0c11846b, []int{20} return fileDescriptor_4dbf1dfe0c11846b, []int{22}
} }
func (m *InvalidateKeyArgs) XXX_Unmarshal(b []byte) error { func (m *InvalidateKeyArgs) XXX_Unmarshal(b []byte) error {
@@ -1704,7 +1774,7 @@ func (m *StorageEntry) Reset() { *m = StorageEntry{} }
func (m *StorageEntry) String() string { return proto.CompactTextString(m) } func (m *StorageEntry) String() string { return proto.CompactTextString(m) }
func (*StorageEntry) ProtoMessage() {} func (*StorageEntry) ProtoMessage() {}
func (*StorageEntry) Descriptor() ([]byte, []int) { func (*StorageEntry) Descriptor() ([]byte, []int) {
return fileDescriptor_4dbf1dfe0c11846b, []int{21} return fileDescriptor_4dbf1dfe0c11846b, []int{23}
} }
func (m *StorageEntry) XXX_Unmarshal(b []byte) error { func (m *StorageEntry) XXX_Unmarshal(b []byte) error {
@@ -1757,7 +1827,7 @@ func (m *StorageListArgs) Reset() { *m = StorageListArgs{} }
func (m *StorageListArgs) String() string { return proto.CompactTextString(m) } func (m *StorageListArgs) String() string { return proto.CompactTextString(m) }
func (*StorageListArgs) ProtoMessage() {} func (*StorageListArgs) ProtoMessage() {}
func (*StorageListArgs) Descriptor() ([]byte, []int) { func (*StorageListArgs) Descriptor() ([]byte, []int) {
return fileDescriptor_4dbf1dfe0c11846b, []int{22} return fileDescriptor_4dbf1dfe0c11846b, []int{24}
} }
func (m *StorageListArgs) XXX_Unmarshal(b []byte) error { func (m *StorageListArgs) XXX_Unmarshal(b []byte) error {
@@ -1797,7 +1867,7 @@ func (m *StorageListReply) Reset() { *m = StorageListReply{} }
func (m *StorageListReply) String() string { return proto.CompactTextString(m) } func (m *StorageListReply) String() string { return proto.CompactTextString(m) }
func (*StorageListReply) ProtoMessage() {} func (*StorageListReply) ProtoMessage() {}
func (*StorageListReply) Descriptor() ([]byte, []int) { func (*StorageListReply) Descriptor() ([]byte, []int) {
return fileDescriptor_4dbf1dfe0c11846b, []int{23} return fileDescriptor_4dbf1dfe0c11846b, []int{25}
} }
func (m *StorageListReply) XXX_Unmarshal(b []byte) error { func (m *StorageListReply) XXX_Unmarshal(b []byte) error {
@@ -1843,7 +1913,7 @@ func (m *StorageGetArgs) Reset() { *m = StorageGetArgs{} }
func (m *StorageGetArgs) String() string { return proto.CompactTextString(m) } func (m *StorageGetArgs) String() string { return proto.CompactTextString(m) }
func (*StorageGetArgs) ProtoMessage() {} func (*StorageGetArgs) ProtoMessage() {}
func (*StorageGetArgs) Descriptor() ([]byte, []int) { func (*StorageGetArgs) Descriptor() ([]byte, []int) {
return fileDescriptor_4dbf1dfe0c11846b, []int{24} return fileDescriptor_4dbf1dfe0c11846b, []int{26}
} }
func (m *StorageGetArgs) XXX_Unmarshal(b []byte) error { func (m *StorageGetArgs) XXX_Unmarshal(b []byte) error {
@@ -1883,7 +1953,7 @@ func (m *StorageGetReply) Reset() { *m = StorageGetReply{} }
func (m *StorageGetReply) String() string { return proto.CompactTextString(m) } func (m *StorageGetReply) String() string { return proto.CompactTextString(m) }
func (*StorageGetReply) ProtoMessage() {} func (*StorageGetReply) ProtoMessage() {}
func (*StorageGetReply) Descriptor() ([]byte, []int) { func (*StorageGetReply) Descriptor() ([]byte, []int) {
return fileDescriptor_4dbf1dfe0c11846b, []int{25} return fileDescriptor_4dbf1dfe0c11846b, []int{27}
} }
func (m *StorageGetReply) XXX_Unmarshal(b []byte) error { func (m *StorageGetReply) XXX_Unmarshal(b []byte) error {
@@ -1929,7 +1999,7 @@ func (m *StoragePutArgs) Reset() { *m = StoragePutArgs{} }
func (m *StoragePutArgs) String() string { return proto.CompactTextString(m) } func (m *StoragePutArgs) String() string { return proto.CompactTextString(m) }
func (*StoragePutArgs) ProtoMessage() {} func (*StoragePutArgs) ProtoMessage() {}
func (*StoragePutArgs) Descriptor() ([]byte, []int) { func (*StoragePutArgs) Descriptor() ([]byte, []int) {
return fileDescriptor_4dbf1dfe0c11846b, []int{26} return fileDescriptor_4dbf1dfe0c11846b, []int{28}
} }
func (m *StoragePutArgs) XXX_Unmarshal(b []byte) error { func (m *StoragePutArgs) XXX_Unmarshal(b []byte) error {
@@ -1968,7 +2038,7 @@ func (m *StoragePutReply) Reset() { *m = StoragePutReply{} }
func (m *StoragePutReply) String() string { return proto.CompactTextString(m) } func (m *StoragePutReply) String() string { return proto.CompactTextString(m) }
func (*StoragePutReply) ProtoMessage() {} func (*StoragePutReply) ProtoMessage() {}
func (*StoragePutReply) Descriptor() ([]byte, []int) { func (*StoragePutReply) Descriptor() ([]byte, []int) {
return fileDescriptor_4dbf1dfe0c11846b, []int{27} return fileDescriptor_4dbf1dfe0c11846b, []int{29}
} }
func (m *StoragePutReply) XXX_Unmarshal(b []byte) error { func (m *StoragePutReply) XXX_Unmarshal(b []byte) error {
@@ -2007,7 +2077,7 @@ func (m *StorageDeleteArgs) Reset() { *m = StorageDeleteArgs{} }
func (m *StorageDeleteArgs) String() string { return proto.CompactTextString(m) } func (m *StorageDeleteArgs) String() string { return proto.CompactTextString(m) }
func (*StorageDeleteArgs) ProtoMessage() {} func (*StorageDeleteArgs) ProtoMessage() {}
func (*StorageDeleteArgs) Descriptor() ([]byte, []int) { func (*StorageDeleteArgs) Descriptor() ([]byte, []int) {
return fileDescriptor_4dbf1dfe0c11846b, []int{28} return fileDescriptor_4dbf1dfe0c11846b, []int{30}
} }
func (m *StorageDeleteArgs) XXX_Unmarshal(b []byte) error { func (m *StorageDeleteArgs) XXX_Unmarshal(b []byte) error {
@@ -2046,7 +2116,7 @@ func (m *StorageDeleteReply) Reset() { *m = StorageDeleteReply{} }
func (m *StorageDeleteReply) String() string { return proto.CompactTextString(m) } func (m *StorageDeleteReply) String() string { return proto.CompactTextString(m) }
func (*StorageDeleteReply) ProtoMessage() {} func (*StorageDeleteReply) ProtoMessage() {}
func (*StorageDeleteReply) Descriptor() ([]byte, []int) { func (*StorageDeleteReply) Descriptor() ([]byte, []int) {
return fileDescriptor_4dbf1dfe0c11846b, []int{29} return fileDescriptor_4dbf1dfe0c11846b, []int{31}
} }
func (m *StorageDeleteReply) XXX_Unmarshal(b []byte) error { func (m *StorageDeleteReply) XXX_Unmarshal(b []byte) error {
@@ -2085,7 +2155,7 @@ func (m *TTLReply) Reset() { *m = TTLReply{} }
func (m *TTLReply) String() string { return proto.CompactTextString(m) } func (m *TTLReply) String() string { return proto.CompactTextString(m) }
func (*TTLReply) ProtoMessage() {} func (*TTLReply) ProtoMessage() {}
func (*TTLReply) Descriptor() ([]byte, []int) { func (*TTLReply) Descriptor() ([]byte, []int) {
return fileDescriptor_4dbf1dfe0c11846b, []int{30} return fileDescriptor_4dbf1dfe0c11846b, []int{32}
} }
func (m *TTLReply) XXX_Unmarshal(b []byte) error { func (m *TTLReply) XXX_Unmarshal(b []byte) error {
@@ -2125,7 +2195,7 @@ func (m *SudoPrivilegeArgs) Reset() { *m = SudoPrivilegeArgs{} }
func (m *SudoPrivilegeArgs) String() string { return proto.CompactTextString(m) } func (m *SudoPrivilegeArgs) String() string { return proto.CompactTextString(m) }
func (*SudoPrivilegeArgs) ProtoMessage() {} func (*SudoPrivilegeArgs) ProtoMessage() {}
func (*SudoPrivilegeArgs) Descriptor() ([]byte, []int) { func (*SudoPrivilegeArgs) Descriptor() ([]byte, []int) {
return fileDescriptor_4dbf1dfe0c11846b, []int{31} return fileDescriptor_4dbf1dfe0c11846b, []int{33}
} }
func (m *SudoPrivilegeArgs) XXX_Unmarshal(b []byte) error { func (m *SudoPrivilegeArgs) XXX_Unmarshal(b []byte) error {
@@ -2171,7 +2241,7 @@ func (m *SudoPrivilegeReply) Reset() { *m = SudoPrivilegeReply{} }
func (m *SudoPrivilegeReply) String() string { return proto.CompactTextString(m) } func (m *SudoPrivilegeReply) String() string { return proto.CompactTextString(m) }
func (*SudoPrivilegeReply) ProtoMessage() {} func (*SudoPrivilegeReply) ProtoMessage() {}
func (*SudoPrivilegeReply) Descriptor() ([]byte, []int) { func (*SudoPrivilegeReply) Descriptor() ([]byte, []int) {
return fileDescriptor_4dbf1dfe0c11846b, []int{32} return fileDescriptor_4dbf1dfe0c11846b, []int{34}
} }
func (m *SudoPrivilegeReply) XXX_Unmarshal(b []byte) error { func (m *SudoPrivilegeReply) XXX_Unmarshal(b []byte) error {
@@ -2210,7 +2280,7 @@ func (m *TaintedReply) Reset() { *m = TaintedReply{} }
func (m *TaintedReply) String() string { return proto.CompactTextString(m) } func (m *TaintedReply) String() string { return proto.CompactTextString(m) }
func (*TaintedReply) ProtoMessage() {} func (*TaintedReply) ProtoMessage() {}
func (*TaintedReply) Descriptor() ([]byte, []int) { func (*TaintedReply) Descriptor() ([]byte, []int) {
return fileDescriptor_4dbf1dfe0c11846b, []int{33} return fileDescriptor_4dbf1dfe0c11846b, []int{35}
} }
func (m *TaintedReply) XXX_Unmarshal(b []byte) error { func (m *TaintedReply) XXX_Unmarshal(b []byte) error {
@@ -2249,7 +2319,7 @@ func (m *CachingDisabledReply) Reset() { *m = CachingDisabledReply{} }
func (m *CachingDisabledReply) String() string { return proto.CompactTextString(m) } func (m *CachingDisabledReply) String() string { return proto.CompactTextString(m) }
func (*CachingDisabledReply) ProtoMessage() {} func (*CachingDisabledReply) ProtoMessage() {}
func (*CachingDisabledReply) Descriptor() ([]byte, []int) { func (*CachingDisabledReply) Descriptor() ([]byte, []int) {
return fileDescriptor_4dbf1dfe0c11846b, []int{34} return fileDescriptor_4dbf1dfe0c11846b, []int{36}
} }
func (m *CachingDisabledReply) XXX_Unmarshal(b []byte) error { func (m *CachingDisabledReply) XXX_Unmarshal(b []byte) error {
@@ -2288,7 +2358,7 @@ func (m *ReplicationStateReply) Reset() { *m = ReplicationStateReply{} }
func (m *ReplicationStateReply) String() string { return proto.CompactTextString(m) } func (m *ReplicationStateReply) String() string { return proto.CompactTextString(m) }
func (*ReplicationStateReply) ProtoMessage() {} func (*ReplicationStateReply) ProtoMessage() {}
func (*ReplicationStateReply) Descriptor() ([]byte, []int) { func (*ReplicationStateReply) Descriptor() ([]byte, []int) {
return fileDescriptor_4dbf1dfe0c11846b, []int{35} return fileDescriptor_4dbf1dfe0c11846b, []int{37}
} }
func (m *ReplicationStateReply) XXX_Unmarshal(b []byte) error { func (m *ReplicationStateReply) XXX_Unmarshal(b []byte) error {
@@ -2329,7 +2399,7 @@ func (m *ResponseWrapDataArgs) Reset() { *m = ResponseWrapDataArgs{} }
func (m *ResponseWrapDataArgs) String() string { return proto.CompactTextString(m) } func (m *ResponseWrapDataArgs) String() string { return proto.CompactTextString(m) }
func (*ResponseWrapDataArgs) ProtoMessage() {} func (*ResponseWrapDataArgs) ProtoMessage() {}
func (*ResponseWrapDataArgs) Descriptor() ([]byte, []int) { func (*ResponseWrapDataArgs) Descriptor() ([]byte, []int) {
return fileDescriptor_4dbf1dfe0c11846b, []int{36} return fileDescriptor_4dbf1dfe0c11846b, []int{38}
} }
func (m *ResponseWrapDataArgs) XXX_Unmarshal(b []byte) error { func (m *ResponseWrapDataArgs) XXX_Unmarshal(b []byte) error {
@@ -2383,7 +2453,7 @@ func (m *ResponseWrapDataReply) Reset() { *m = ResponseWrapDataReply{} }
func (m *ResponseWrapDataReply) String() string { return proto.CompactTextString(m) } func (m *ResponseWrapDataReply) String() string { return proto.CompactTextString(m) }
func (*ResponseWrapDataReply) ProtoMessage() {} func (*ResponseWrapDataReply) ProtoMessage() {}
func (*ResponseWrapDataReply) Descriptor() ([]byte, []int) { func (*ResponseWrapDataReply) Descriptor() ([]byte, []int) {
return fileDescriptor_4dbf1dfe0c11846b, []int{37} return fileDescriptor_4dbf1dfe0c11846b, []int{39}
} }
func (m *ResponseWrapDataReply) XXX_Unmarshal(b []byte) error { func (m *ResponseWrapDataReply) XXX_Unmarshal(b []byte) error {
@@ -2429,7 +2499,7 @@ func (m *MlockEnabledReply) Reset() { *m = MlockEnabledReply{} }
func (m *MlockEnabledReply) String() string { return proto.CompactTextString(m) } func (m *MlockEnabledReply) String() string { return proto.CompactTextString(m) }
func (*MlockEnabledReply) ProtoMessage() {} func (*MlockEnabledReply) ProtoMessage() {}
func (*MlockEnabledReply) Descriptor() ([]byte, []int) { func (*MlockEnabledReply) Descriptor() ([]byte, []int) {
return fileDescriptor_4dbf1dfe0c11846b, []int{38} return fileDescriptor_4dbf1dfe0c11846b, []int{40}
} }
func (m *MlockEnabledReply) XXX_Unmarshal(b []byte) error { func (m *MlockEnabledReply) XXX_Unmarshal(b []byte) error {
@@ -2468,7 +2538,7 @@ func (m *LocalMountReply) Reset() { *m = LocalMountReply{} }
func (m *LocalMountReply) String() string { return proto.CompactTextString(m) } func (m *LocalMountReply) String() string { return proto.CompactTextString(m) }
func (*LocalMountReply) ProtoMessage() {} func (*LocalMountReply) ProtoMessage() {}
func (*LocalMountReply) Descriptor() ([]byte, []int) { func (*LocalMountReply) Descriptor() ([]byte, []int) {
return fileDescriptor_4dbf1dfe0c11846b, []int{39} return fileDescriptor_4dbf1dfe0c11846b, []int{41}
} }
func (m *LocalMountReply) XXX_Unmarshal(b []byte) error { func (m *LocalMountReply) XXX_Unmarshal(b []byte) error {
@@ -2507,7 +2577,7 @@ func (m *EntityInfoArgs) Reset() { *m = EntityInfoArgs{} }
func (m *EntityInfoArgs) String() string { return proto.CompactTextString(m) } func (m *EntityInfoArgs) String() string { return proto.CompactTextString(m) }
func (*EntityInfoArgs) ProtoMessage() {} func (*EntityInfoArgs) ProtoMessage() {}
func (*EntityInfoArgs) Descriptor() ([]byte, []int) { func (*EntityInfoArgs) Descriptor() ([]byte, []int) {
return fileDescriptor_4dbf1dfe0c11846b, []int{40} return fileDescriptor_4dbf1dfe0c11846b, []int{42}
} }
func (m *EntityInfoArgs) XXX_Unmarshal(b []byte) error { func (m *EntityInfoArgs) XXX_Unmarshal(b []byte) error {
@@ -2547,7 +2617,7 @@ func (m *EntityInfoReply) Reset() { *m = EntityInfoReply{} }
func (m *EntityInfoReply) String() string { return proto.CompactTextString(m) } func (m *EntityInfoReply) String() string { return proto.CompactTextString(m) }
func (*EntityInfoReply) ProtoMessage() {} func (*EntityInfoReply) ProtoMessage() {}
func (*EntityInfoReply) Descriptor() ([]byte, []int) { func (*EntityInfoReply) Descriptor() ([]byte, []int) {
return fileDescriptor_4dbf1dfe0c11846b, []int{41} return fileDescriptor_4dbf1dfe0c11846b, []int{43}
} }
func (m *EntityInfoReply) XXX_Unmarshal(b []byte) error { func (m *EntityInfoReply) XXX_Unmarshal(b []byte) error {
@@ -2594,7 +2664,7 @@ func (m *PluginEnvReply) Reset() { *m = PluginEnvReply{} }
func (m *PluginEnvReply) String() string { return proto.CompactTextString(m) } func (m *PluginEnvReply) String() string { return proto.CompactTextString(m) }
func (*PluginEnvReply) ProtoMessage() {} func (*PluginEnvReply) ProtoMessage() {}
func (*PluginEnvReply) Descriptor() ([]byte, []int) { func (*PluginEnvReply) Descriptor() ([]byte, []int) {
return fileDescriptor_4dbf1dfe0c11846b, []int{42} return fileDescriptor_4dbf1dfe0c11846b, []int{44}
} }
func (m *PluginEnvReply) XXX_Unmarshal(b []byte) error { func (m *PluginEnvReply) XXX_Unmarshal(b []byte) error {
@@ -2641,7 +2711,7 @@ func (m *Connection) Reset() { *m = Connection{} }
func (m *Connection) String() string { return proto.CompactTextString(m) } func (m *Connection) String() string { return proto.CompactTextString(m) }
func (*Connection) ProtoMessage() {} func (*Connection) ProtoMessage() {}
func (*Connection) Descriptor() ([]byte, []int) { func (*Connection) Descriptor() ([]byte, []int) {
return fileDescriptor_4dbf1dfe0c11846b, []int{43} return fileDescriptor_4dbf1dfe0c11846b, []int{45}
} }
func (m *Connection) XXX_Unmarshal(b []byte) error { func (m *Connection) XXX_Unmarshal(b []byte) error {
@@ -2688,6 +2758,8 @@ func init() {
proto.RegisterType((*RequestWrapInfo)(nil), "pb.RequestWrapInfo") proto.RegisterType((*RequestWrapInfo)(nil), "pb.RequestWrapInfo")
proto.RegisterType((*HandleRequestArgs)(nil), "pb.HandleRequestArgs") proto.RegisterType((*HandleRequestArgs)(nil), "pb.HandleRequestArgs")
proto.RegisterType((*HandleRequestReply)(nil), "pb.HandleRequestReply") proto.RegisterType((*HandleRequestReply)(nil), "pb.HandleRequestReply")
proto.RegisterType((*InitializeArgs)(nil), "pb.InitializeArgs")
proto.RegisterType((*InitializeReply)(nil), "pb.InitializeReply")
proto.RegisterType((*SpecialPathsReply)(nil), "pb.SpecialPathsReply") proto.RegisterType((*SpecialPathsReply)(nil), "pb.SpecialPathsReply")
proto.RegisterType((*HandleExistenceCheckArgs)(nil), "pb.HandleExistenceCheckArgs") proto.RegisterType((*HandleExistenceCheckArgs)(nil), "pb.HandleExistenceCheckArgs")
proto.RegisterType((*HandleExistenceCheckReply)(nil), "pb.HandleExistenceCheckReply") proto.RegisterType((*HandleExistenceCheckReply)(nil), "pb.HandleExistenceCheckReply")
@@ -2724,165 +2796,167 @@ func init() {
func init() { proto.RegisterFile("sdk/plugin/pb/backend.proto", fileDescriptor_4dbf1dfe0c11846b) } func init() { proto.RegisterFile("sdk/plugin/pb/backend.proto", fileDescriptor_4dbf1dfe0c11846b) }
var fileDescriptor_4dbf1dfe0c11846b = []byte{ var fileDescriptor_4dbf1dfe0c11846b = []byte{
// 2519 bytes of a gzipped FileDescriptorProto // 2556 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x59, 0xdb, 0x72, 0x1b, 0xc7, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x59, 0x4b, 0x73, 0xe3, 0xc6,
0xd1, 0x2e, 0x00, 0xc4, 0xa9, 0x71, 0x22, 0x46, 0xb4, 0xfe, 0x15, 0x24, 0xff, 0x82, 0xd7, 0x91, 0x11, 0x2e, 0x92, 0xe2, 0xab, 0xf9, 0x9e, 0x95, 0x37, 0x58, 0xee, 0x3a, 0x2b, 0xc3, 0xd9, 0x35,
0x0c, 0x33, 0x36, 0x68, 0xd1, 0x71, 0x2c, 0x27, 0x65, 0xa7, 0x68, 0x8a, 0x96, 0x19, 0x93, 0x36, 0xad, 0xd8, 0x94, 0x57, 0x1b, 0xc7, 0xeb, 0xa4, 0xec, 0x94, 0xac, 0x95, 0xd7, 0x8a, 0x25, 0x5b,
0x6b, 0x09, 0xc7, 0x39, 0x55, 0xc1, 0x83, 0xdd, 0x21, 0xb8, 0xc5, 0xc5, 0xee, 0x66, 0x76, 0x96, 0x05, 0xd1, 0x71, 0x5e, 0x55, 0xf4, 0x10, 0x18, 0x51, 0x28, 0x81, 0x00, 0x32, 0x18, 0x68, 0xc5,
0x22, 0xae, 0xf2, 0x16, 0x79, 0x8d, 0xdc, 0xe6, 0x2e, 0x77, 0x29, 0x57, 0xee, 0xf3, 0x0a, 0xb9, 0x5c, 0xf2, 0x2f, 0xf2, 0x0f, 0x72, 0xce, 0x35, 0xb7, 0xdc, 0x52, 0xae, 0xdc, 0xf3, 0x17, 0xf2,
0xcc, 0x33, 0xa4, 0xa6, 0x67, 0xf6, 0x04, 0x80, 0x96, 0x5c, 0xe5, 0xdc, 0xcd, 0x74, 0xf7, 0x9c, 0x3b, 0x52, 0xd3, 0x33, 0x78, 0x91, 0x94, 0x1f, 0x55, 0xce, 0x6d, 0xa6, 0xbb, 0xe7, 0xd5, 0xf3,
0x7a, 0xbe, 0xfe, 0xba, 0x67, 0x17, 0xee, 0x47, 0xce, 0xd5, 0x5e, 0xe8, 0xc5, 0x73, 0xd7, 0xdf, 0xf5, 0xd7, 0x3d, 0x00, 0xdc, 0x8f, 0x9c, 0xab, 0xbd, 0xd0, 0x8b, 0xe7, 0xae, 0xbf, 0x17, 0xce,
0x0b, 0x67, 0x7b, 0x33, 0x6a, 0x5f, 0x31, 0xdf, 0x19, 0x87, 0x3c, 0x10, 0x01, 0x29, 0x87, 0xb3, 0xf6, 0x66, 0xd4, 0xbe, 0x62, 0xbe, 0x33, 0x0e, 0x79, 0x20, 0x02, 0x52, 0x0e, 0x67, 0xc3, 0x87,
0xc1, 0xc3, 0x79, 0x10, 0xcc, 0x3d, 0xb6, 0x87, 0x92, 0x59, 0x7c, 0xb1, 0x27, 0xdc, 0x05, 0x8b, 0xf3, 0x20, 0x98, 0x7b, 0x6c, 0x0f, 0x25, 0xb3, 0xf8, 0x62, 0x4f, 0xb8, 0x0b, 0x16, 0x09, 0xba,
0x04, 0x5d, 0x84, 0xca, 0x68, 0x30, 0x90, 0x33, 0x78, 0xc1, 0xdc, 0xb5, 0xa9, 0xb7, 0xe7, 0x3a, 0x08, 0x95, 0xd1, 0x70, 0x28, 0x67, 0xf0, 0x82, 0xb9, 0x6b, 0x53, 0x6f, 0xcf, 0x75, 0x98, 0x2f,
0xcc, 0x17, 0xae, 0x58, 0x6a, 0x9d, 0x91, 0xd7, 0xa9, 0x55, 0x94, 0xc6, 0xac, 0x43, 0xf5, 0x68, 0x5c, 0xb1, 0xd4, 0x3a, 0x23, 0xaf, 0x53, 0xab, 0x28, 0x8d, 0x59, 0x87, 0xea, 0xd1, 0x22, 0x14,
0x11, 0x8a, 0xa5, 0x39, 0x84, 0xda, 0xe7, 0x8c, 0x3a, 0x8c, 0x93, 0xbb, 0x50, 0xbb, 0xc4, 0x96, 0x4b, 0x73, 0x07, 0x6a, 0x9f, 0x30, 0xea, 0x30, 0x4e, 0xee, 0x42, 0xed, 0x12, 0x5b, 0x46, 0x69,
0x51, 0x1a, 0x56, 0x46, 0x4d, 0x4b, 0xf7, 0xcc, 0x3f, 0x00, 0x9c, 0xc9, 0x31, 0x47, 0x9c, 0x07, 0xa7, 0x32, 0x6a, 0x5a, 0xba, 0x67, 0xfe, 0x01, 0xe0, 0x4c, 0x8e, 0x39, 0xe2, 0x3c, 0xe0, 0xe4,
0x9c, 0xdc, 0x83, 0x06, 0xe3, 0x7c, 0x2a, 0x96, 0x21, 0x33, 0x4a, 0xc3, 0xd2, 0xa8, 0x63, 0xd5, 0x1e, 0x34, 0x18, 0xe7, 0x53, 0xb1, 0x0c, 0x99, 0x51, 0xda, 0x29, 0x8d, 0x3a, 0x56, 0x9d, 0x71,
0x19, 0xe7, 0x93, 0x65, 0xc8, 0xc8, 0xff, 0x81, 0x6c, 0x4e, 0x17, 0xd1, 0xdc, 0x28, 0x0f, 0x4b, 0x3e, 0x59, 0x86, 0x8c, 0xfc, 0x08, 0x64, 0x73, 0xba, 0x88, 0xe6, 0x46, 0x79, 0xa7, 0x24, 0x67,
0x72, 0x06, 0xc6, 0xf9, 0x69, 0x34, 0x4f, 0xc6, 0xd8, 0x81, 0xc3, 0x8c, 0xca, 0xb0, 0x34, 0xaa, 0x60, 0x9c, 0x9f, 0x46, 0xf3, 0x64, 0x8c, 0x1d, 0x38, 0xcc, 0xa8, 0xec, 0x94, 0x46, 0x15, 0x1c,
0xe0, 0x98, 0xc3, 0xc0, 0x61, 0xe6, 0x5f, 0x4a, 0x50, 0x3d, 0xa3, 0xe2, 0x32, 0x22, 0x04, 0xb6, 0x73, 0x18, 0x38, 0xcc, 0xfc, 0x6b, 0x09, 0xaa, 0x67, 0x54, 0x5c, 0x46, 0x84, 0xc0, 0x16, 0x0f,
0x78, 0x10, 0x08, 0xbd, 0x38, 0xb6, 0xc9, 0x08, 0x7a, 0xb1, 0x4f, 0x63, 0x71, 0x29, 0x4f, 0x65, 0x02, 0xa1, 0x17, 0xc7, 0x36, 0x19, 0x41, 0x2f, 0xf6, 0x69, 0x2c, 0x2e, 0xe5, 0xa9, 0x6c, 0x2a,
0x53, 0xc1, 0x1c, 0xa3, 0x8c, 0xea, 0x55, 0x31, 0x79, 0x13, 0x3a, 0x5e, 0x60, 0x53, 0x6f, 0x1a, 0x98, 0x63, 0x94, 0x51, 0xbd, 0x2a, 0x26, 0xaf, 0x43, 0xc7, 0x0b, 0x6c, 0xea, 0x4d, 0x23, 0x11,
0x89, 0x80, 0xd3, 0xb9, 0x5c, 0x47, 0xda, 0xb5, 0x51, 0x78, 0xae, 0x64, 0x64, 0x17, 0xfa, 0x11, 0x70, 0x3a, 0x97, 0xeb, 0x48, 0xbb, 0x36, 0x0a, 0xcf, 0x95, 0x8c, 0xec, 0xc2, 0x20, 0x62, 0xd4,
0xa3, 0xde, 0xf4, 0x05, 0xa7, 0x61, 0x6a, 0xb8, 0xa5, 0x26, 0x94, 0x8a, 0x6f, 0x38, 0x0d, 0xb5, 0x9b, 0xbe, 0xe4, 0x34, 0x4c, 0x0d, 0xb7, 0xd4, 0x84, 0x52, 0xf1, 0x25, 0xa7, 0xa1, 0xb6, 0x35,
0xad, 0xf9, 0xf7, 0x1a, 0xd4, 0x2d, 0xf6, 0xa7, 0x98, 0x45, 0x82, 0x74, 0xa1, 0xec, 0x3a, 0x78, 0xff, 0x59, 0x83, 0xba, 0xc5, 0xfe, 0x14, 0xb3, 0x48, 0x90, 0x2e, 0x94, 0x5d, 0x07, 0x4f, 0xdb,
0xda, 0xa6, 0x55, 0x76, 0x1d, 0x32, 0x06, 0x62, 0xb1, 0xd0, 0x93, 0x4b, 0xbb, 0x81, 0x7f, 0xe8, 0xb4, 0xca, 0xae, 0x43, 0xc6, 0x40, 0x2c, 0x16, 0x7a, 0x72, 0x69, 0x37, 0xf0, 0x0f, 0xbd, 0x38,
0xc5, 0x91, 0x60, 0x5c, 0x9f, 0x79, 0x83, 0x86, 0x3c, 0x80, 0x66, 0x10, 0x32, 0x8e, 0x32, 0x74, 0x12, 0x8c, 0xeb, 0x33, 0x6f, 0xd0, 0x90, 0x07, 0xd0, 0x0c, 0x42, 0xc6, 0x51, 0x86, 0x0e, 0x68,
0x40, 0xd3, 0xca, 0x04, 0xf2, 0xe0, 0x21, 0x15, 0x97, 0xc6, 0x16, 0x2a, 0xb0, 0x2d, 0x65, 0x0e, 0x5a, 0x99, 0x40, 0x1e, 0x3c, 0xa4, 0xe2, 0xd2, 0xd8, 0x42, 0x05, 0xb6, 0xa5, 0xcc, 0xa1, 0x82,
0x15, 0xd4, 0xa8, 0x2a, 0x99, 0x6c, 0x13, 0x13, 0x6a, 0x11, 0xb3, 0x39, 0x13, 0x46, 0x6d, 0x58, 0x1a, 0x55, 0x25, 0x93, 0x6d, 0x62, 0x42, 0x2d, 0x62, 0x36, 0x67, 0xc2, 0xa8, 0xed, 0x94, 0x46,
0x1a, 0xb5, 0xf6, 0x61, 0x1c, 0xce, 0xc6, 0xe7, 0x28, 0xb1, 0xb4, 0x86, 0x3c, 0x80, 0x2d, 0xe9, 0xad, 0x7d, 0x18, 0x87, 0xb3, 0xf1, 0x39, 0x4a, 0x2c, 0xad, 0x21, 0x0f, 0x60, 0x4b, 0xfa, 0xc5,
0x17, 0xa3, 0x8e, 0x16, 0x0d, 0x69, 0x71, 0x10, 0x8b, 0x4b, 0x0b, 0xa5, 0x64, 0x1f, 0xea, 0xea, 0xa8, 0xa3, 0x45, 0x43, 0x5a, 0x1c, 0xc4, 0xe2, 0xd2, 0x42, 0x29, 0xd9, 0x87, 0xba, 0xba, 0xd3,
0x4e, 0x23, 0xa3, 0x31, 0xac, 0x8c, 0x5a, 0xfb, 0x86, 0x34, 0xd0, 0xa7, 0x1c, 0x2b, 0x18, 0x44, 0xc8, 0x68, 0xec, 0x54, 0x46, 0xad, 0x7d, 0x43, 0x1a, 0xe8, 0x53, 0x8e, 0x15, 0x0c, 0xa2, 0x23,
0x47, 0xbe, 0xe0, 0x4b, 0x2b, 0x31, 0x24, 0x6f, 0x40, 0xdb, 0xf6, 0x5c, 0xe6, 0x8b, 0xa9, 0x08, 0x5f, 0xf0, 0xa5, 0x95, 0x18, 0x92, 0xd7, 0xa0, 0x6d, 0x7b, 0x2e, 0xf3, 0xc5, 0x54, 0x04, 0x57,
0xae, 0x98, 0x6f, 0x34, 0x71, 0x47, 0x2d, 0x25, 0x9b, 0x48, 0x11, 0xd9, 0x87, 0xd7, 0xf2, 0x26, 0xcc, 0x37, 0x9a, 0xb8, 0xa3, 0x96, 0x92, 0x4d, 0xa4, 0x88, 0xec, 0xc3, 0x2b, 0x79, 0x93, 0x29,
0x53, 0x6a, 0xdb, 0x2c, 0x8a, 0x02, 0x6e, 0x00, 0xda, 0xde, 0xc9, 0xd9, 0x1e, 0x68, 0x95, 0x9c, 0xb5, 0x6d, 0x16, 0x45, 0x01, 0x37, 0x00, 0x6d, 0xef, 0xe4, 0x6c, 0x0f, 0xb4, 0x4a, 0x4e, 0xeb,
0xd6, 0x71, 0xa3, 0xd0, 0xa3, 0xcb, 0xa9, 0x4f, 0x17, 0xcc, 0x68, 0xa9, 0x69, 0xb5, 0xec, 0x4b, 0xb8, 0x51, 0xe8, 0xd1, 0xe5, 0xd4, 0xa7, 0x0b, 0x66, 0xb4, 0xd4, 0xb4, 0x5a, 0xf6, 0x19, 0x5d,
0xba, 0x60, 0xe4, 0x21, 0xb4, 0x16, 0x41, 0xec, 0x8b, 0x69, 0x18, 0xb8, 0xbe, 0x30, 0xda, 0x68, 0x30, 0xf2, 0x10, 0x5a, 0x8b, 0x20, 0xf6, 0xc5, 0x34, 0x0c, 0x5c, 0x5f, 0x18, 0x6d, 0xb4, 0x00,
0x01, 0x28, 0x3a, 0x93, 0x12, 0xf2, 0x3a, 0xa8, 0x9e, 0x02, 0x63, 0x47, 0xf9, 0x15, 0x25, 0x08, 0x14, 0x9d, 0x49, 0x09, 0x79, 0x15, 0x54, 0x4f, 0x81, 0xb1, 0xa3, 0xfc, 0x8a, 0x12, 0x84, 0xe3,
0xc7, 0x47, 0xd0, 0x55, 0xea, 0x74, 0x3f, 0x5d, 0x34, 0xe9, 0xa0, 0x34, 0xdd, 0xc9, 0x7b, 0xd0, 0x23, 0xe8, 0x2a, 0x75, 0xba, 0x9f, 0x2e, 0x9a, 0x74, 0x50, 0x9a, 0xee, 0xe4, 0x1d, 0x68, 0x22,
0x44, 0x3c, 0xb8, 0xfe, 0x45, 0x60, 0xf4, 0xd0, 0x6f, 0x77, 0x72, 0x6e, 0x91, 0x98, 0x38, 0xf6, 0x1e, 0x5c, 0xff, 0x22, 0x30, 0x7a, 0xe8, 0xb7, 0x3b, 0x39, 0xb7, 0x48, 0x4c, 0x1c, 0xfb, 0x17,
0x2f, 0x02, 0xab, 0xf1, 0x42, 0xb7, 0xc8, 0xc7, 0x70, 0xbf, 0x70, 0x5e, 0xce, 0x16, 0xd4, 0xf5, 0x81, 0xd5, 0x78, 0xa9, 0x5b, 0xe4, 0x03, 0xb8, 0x5f, 0x38, 0x2f, 0x67, 0x0b, 0xea, 0xfa, 0xae,
0x5d, 0x7f, 0x3e, 0x8d, 0x23, 0x16, 0x19, 0xdb, 0x88, 0x70, 0x23, 0x77, 0x6a, 0x2b, 0x31, 0xf8, 0x3f, 0x9f, 0xc6, 0x11, 0x8b, 0x8c, 0x3e, 0x22, 0xdc, 0xc8, 0x9d, 0xda, 0x4a, 0x0c, 0xbe, 0x88,
0x3a, 0x62, 0x11, 0xb9, 0x0f, 0x4d, 0x15, 0xa4, 0x53, 0xd7, 0x31, 0xfa, 0xb8, 0xa5, 0x86, 0x12, 0x58, 0x44, 0xee, 0x43, 0x53, 0x05, 0xe9, 0xd4, 0x75, 0x8c, 0x01, 0x6e, 0xa9, 0xa1, 0x04, 0xc7,
0x1c, 0x3b, 0xe4, 0x2d, 0xe8, 0x85, 0x81, 0xe7, 0xda, 0xcb, 0x69, 0x70, 0xcd, 0x38, 0x77, 0x1d, 0x0e, 0x79, 0x03, 0x7a, 0x61, 0xe0, 0xb9, 0xf6, 0x72, 0x1a, 0x5c, 0x33, 0xce, 0x5d, 0x87, 0x19,
0x66, 0x90, 0x61, 0x69, 0xd4, 0xb0, 0xba, 0x4a, 0xfc, 0x95, 0x96, 0x6e, 0x0a, 0x8d, 0x3b, 0x68, 0x64, 0xa7, 0x34, 0x6a, 0x58, 0x5d, 0x25, 0xfe, 0x5c, 0x4b, 0x37, 0x85, 0xc6, 0x1d, 0x34, 0x5c,
0xb8, 0x16, 0x1a, 0x63, 0x00, 0x3b, 0xf0, 0x7d, 0x66, 0x23, 0xfc, 0x76, 0xf0, 0x84, 0x5d, 0x79, 0x0b, 0x8d, 0x31, 0x80, 0x1d, 0xf8, 0x3e, 0xb3, 0x11, 0x7e, 0xdb, 0x78, 0xc2, 0xae, 0x3c, 0xe1,
0xc2, 0xc3, 0x54, 0x6a, 0xe5, 0x2c, 0x06, 0x9f, 0x41, 0x3b, 0x0f, 0x05, 0xb2, 0x0d, 0x95, 0x2b, 0x61, 0x2a, 0xb5, 0x72, 0x16, 0xc3, 0x8f, 0xa1, 0x9d, 0x87, 0x02, 0xe9, 0x43, 0xe5, 0x8a, 0x2d,
0xb6, 0xd4, 0xf0, 0x97, 0x4d, 0x32, 0x84, 0xea, 0x35, 0xf5, 0x62, 0x86, 0x90, 0xd7, 0x40, 0x54, 0x35, 0xfc, 0x65, 0x93, 0xec, 0x40, 0xf5, 0x9a, 0x7a, 0x31, 0x43, 0xc8, 0x6b, 0x20, 0xaa, 0x21,
0x43, 0x2c, 0xa5, 0xf8, 0x45, 0xf9, 0x69, 0xc9, 0xfc, 0x77, 0x15, 0xb6, 0x24, 0xf8, 0xc8, 0x07, 0x96, 0x52, 0xfc, 0xa2, 0xfc, 0xac, 0x64, 0xfe, 0xb7, 0x0a, 0x5b, 0x12, 0x7c, 0xe4, 0x5d, 0xe8,
0xd0, 0xf1, 0x18, 0x8d, 0xd8, 0x34, 0x08, 0xe5, 0x02, 0x11, 0x4e, 0xd5, 0xda, 0xdf, 0x96, 0xc3, 0x78, 0x8c, 0x46, 0x6c, 0x1a, 0x84, 0x72, 0x81, 0x08, 0xa7, 0x6a, 0xed, 0xf7, 0xe5, 0xb0, 0x13,
0x4e, 0xa4, 0xe2, 0x2b, 0x25, 0xb7, 0xda, 0x5e, 0xae, 0x27, 0x43, 0xda, 0xf5, 0x05, 0xe3, 0x3e, 0xa9, 0xf8, 0x5c, 0xc9, 0xad, 0xb6, 0x97, 0xeb, 0xc9, 0x90, 0x76, 0x7d, 0xc1, 0xb8, 0x4f, 0xbd,
0xf5, 0xa6, 0x18, 0x0c, 0x2a, 0xc0, 0xda, 0x89, 0xf0, 0x99, 0x0c, 0x8a, 0x55, 0x1c, 0x55, 0xd6, 0x29, 0x06, 0x83, 0x0a, 0xb0, 0x76, 0x22, 0x7c, 0x2e, 0x83, 0x62, 0x15, 0x47, 0x95, 0x75, 0x1c,
0x71, 0x34, 0x80, 0x06, 0xfa, 0xce, 0x65, 0x91, 0x0e, 0xf6, 0xb4, 0x4f, 0xf6, 0xa1, 0xb1, 0x60, 0x0d, 0xa1, 0x81, 0xbe, 0x73, 0x59, 0xa4, 0x83, 0x3d, 0xed, 0x93, 0x7d, 0x68, 0x2c, 0x98, 0xa0,
0x82, 0xea, 0x58, 0x93, 0x21, 0x71, 0x37, 0x89, 0x99, 0xf1, 0xa9, 0x56, 0xa8, 0x80, 0x48, 0xed, 0x3a, 0xd6, 0x64, 0x48, 0xdc, 0x4d, 0x62, 0x66, 0x7c, 0xaa, 0x15, 0x2a, 0x20, 0x52, 0xbb, 0xb5,
0xd6, 0x22, 0xa2, 0xb6, 0x1e, 0x11, 0x03, 0x68, 0xa4, 0xa0, 0xab, 0xab, 0x1b, 0x4e, 0xfa, 0x92, 0x88, 0xa8, 0xad, 0x47, 0xc4, 0x10, 0x1a, 0x29, 0xe8, 0xea, 0xea, 0x86, 0x93, 0xbe, 0xa4, 0xd9,
0x66, 0x43, 0xc6, 0xdd, 0xc0, 0x31, 0x1a, 0x08, 0x14, 0xdd, 0x93, 0x24, 0xe9, 0xc7, 0x0b, 0x05, 0x90, 0x71, 0x37, 0x70, 0x8c, 0x06, 0x02, 0x45, 0xf7, 0x24, 0x49, 0xfa, 0xf1, 0x42, 0x41, 0xa8,
0xa1, 0xa6, 0x22, 0x49, 0x3f, 0x5e, 0xac, 0x23, 0x06, 0x56, 0x10, 0xf3, 0x13, 0xa8, 0x52, 0xcf, 0xa9, 0x48, 0xd2, 0x8f, 0x17, 0xeb, 0x88, 0x81, 0x15, 0xc4, 0xfc, 0x04, 0xaa, 0xd4, 0x73, 0x69,
0xa5, 0x11, 0x86, 0x90, 0xbc, 0x59, 0xcd, 0xf7, 0xe3, 0x03, 0x29, 0xb5, 0x94, 0x92, 0xbc, 0x0f, 0x84, 0x21, 0x24, 0x6f, 0x56, 0xf3, 0xfd, 0xf8, 0x40, 0x4a, 0x2d, 0xa5, 0x24, 0x4f, 0xa1, 0x33,
0x9d, 0x39, 0x0f, 0xe2, 0x70, 0x8a, 0x5d, 0x16, 0x19, 0x6d, 0x3c, 0xed, 0xaa, 0x75, 0x1b, 0x8d, 0xe7, 0x41, 0x1c, 0x4e, 0xb1, 0xcb, 0x22, 0xa3, 0x8d, 0xa7, 0x5d, 0xb5, 0x6e, 0xa3, 0xd1, 0x81,
0x0e, 0x94, 0x8d, 0x8c, 0xc0, 0x59, 0x10, 0xfb, 0xce, 0xd4, 0x76, 0x1d, 0x1e, 0x19, 0x1d, 0x74, 0xb2, 0x91, 0x11, 0x38, 0x0b, 0x62, 0xdf, 0x99, 0xda, 0xae, 0xc3, 0x23, 0xa3, 0x83, 0xce, 0x03,
0x1e, 0xa0, 0xe8, 0x50, 0x4a, 0x64, 0x88, 0xa9, 0x10, 0x48, 0x1d, 0xdc, 0x45, 0x9b, 0x0e, 0x4a, 0x14, 0x1d, 0x4a, 0x89, 0x0c, 0x31, 0x15, 0x02, 0xa9, 0x83, 0xbb, 0x68, 0xd3, 0x41, 0xe9, 0x59,
0xcf, 0x12, 0x2f, 0xff, 0x14, 0xfa, 0x49, 0x62, 0xca, 0x2c, 0x7b, 0x68, 0xb9, 0x9d, 0x28, 0x52, 0xe2, 0xe5, 0x9f, 0xc2, 0x20, 0x49, 0x4c, 0x99, 0x65, 0x0f, 0x2d, 0xfb, 0x89, 0x22, 0x35, 0x1e,
0xe3, 0x11, 0x6c, 0xb3, 0x1b, 0x49, 0xa1, 0xae, 0x98, 0x2e, 0xe8, 0xcd, 0x54, 0x08, 0x4f, 0x87, 0x41, 0x9f, 0xdd, 0x48, 0x0a, 0x75, 0xc5, 0x74, 0x41, 0x6f, 0xa6, 0x42, 0x78, 0x3a, 0xa4, 0xba,
0x54, 0x37, 0x91, 0x9f, 0xd2, 0x9b, 0x89, 0xf0, 0x64, 0xfc, 0xab, 0xd5, 0x31, 0xfe, 0xfb, 0x98, 0x89, 0xfc, 0x94, 0xde, 0x4c, 0x84, 0x27, 0xe3, 0x5f, 0xad, 0x8e, 0xf1, 0x3f, 0xc0, 0x64, 0xd4,
0x8c, 0x9a, 0x28, 0xc1, 0xf8, 0xdf, 0x85, 0xbe, 0x1f, 0x4c, 0x1d, 0x76, 0x41, 0x63, 0x4f, 0xa8, 0x44, 0x09, 0xc6, 0xff, 0x2e, 0x0c, 0xfc, 0x60, 0xea, 0xb0, 0x0b, 0x1a, 0x7b, 0x42, 0xad, 0xbb,
0x75, 0x97, 0x3a, 0x98, 0x7a, 0x7e, 0xf0, 0x4c, 0xc9, 0x71, 0xd9, 0xe5, 0xe0, 0x97, 0xd0, 0x29, 0xd4, 0xc1, 0xd4, 0xf3, 0x83, 0xe7, 0x4a, 0x8e, 0xcb, 0x2e, 0x87, 0xbf, 0x84, 0x4e, 0xe1, 0xba,
0x5c, 0xf7, 0x06, 0xd0, 0xef, 0xe4, 0x41, 0xdf, 0xcc, 0x03, 0xfd, 0x9f, 0x5b, 0x00, 0x78, 0xef, 0x37, 0x80, 0x7e, 0x3b, 0x0f, 0xfa, 0x66, 0x1e, 0xe8, 0xff, 0xde, 0x02, 0xc0, 0x7b, 0x57, 0x43,
0x6a, 0xe8, 0x6a, 0xb6, 0xc8, 0x83, 0xa1, 0xbc, 0x01, 0x0c, 0x94, 0x33, 0x5f, 0x68, 0xe0, 0xea, 0x57, 0xb3, 0x45, 0x1e, 0x0c, 0xe5, 0x0d, 0x60, 0xa0, 0x9c, 0xf9, 0x42, 0x03, 0x57, 0xf7, 0xbe,
0xde, 0xf7, 0x62, 0x36, 0xc9, 0x17, 0xd5, 0x5c, 0xbe, 0x78, 0x07, 0xb6, 0x24, 0x3e, 0x8d, 0x5a, 0x11, 0xb3, 0x49, 0xbe, 0xa8, 0xe6, 0xf2, 0xc5, 0x5b, 0xb0, 0x25, 0xf1, 0x69, 0xd4, 0x32, 0x5a,
0x46, 0xeb, 0xd9, 0x8e, 0x10, 0xc9, 0x0a, 0xc5, 0x68, 0xb5, 0x16, 0x34, 0xf5, 0xf5, 0xa0, 0xc9, 0xcf, 0x76, 0x84, 0x48, 0x56, 0x28, 0x46, 0xab, 0xb5, 0xa0, 0xa9, 0xaf, 0x07, 0x4d, 0x1e, 0x8d,
0xa3, 0xb1, 0x51, 0x44, 0xe3, 0x9b, 0xd0, 0xb1, 0x39, 0xc3, 0xdc, 0x35, 0x95, 0xc5, 0x88, 0x46, 0x8d, 0x22, 0x1a, 0x5f, 0x87, 0x8e, 0xcd, 0x19, 0xe6, 0xae, 0xa9, 0x2c, 0x46, 0x34, 0x5a, 0xdb,
0x6b, 0x3b, 0x11, 0x4e, 0xdc, 0x05, 0x93, 0xfe, 0x93, 0x17, 0x07, 0xa8, 0x92, 0xcd, 0x8d, 0xf7, 0x89, 0x70, 0xe2, 0x2e, 0x98, 0xf4, 0x9f, 0xbc, 0x38, 0x40, 0x95, 0x6c, 0x6e, 0xbc, 0xd7, 0xd6,
0xda, 0xda, 0x78, 0xaf, 0x58, 0x09, 0x78, 0x4c, 0x33, 0x3e, 0xb6, 0x73, 0x51, 0xd3, 0x29, 0x44, 0xc6, 0x7b, 0xc5, 0x4a, 0xc0, 0x63, 0x9a, 0xf1, 0xb1, 0x9d, 0x8b, 0x9a, 0x4e, 0x21, 0x6a, 0x0a,
0x4d, 0x21, 0x34, 0xba, 0x2b, 0xa1, 0xb1, 0x82, 0xdf, 0xde, 0x1a, 0x7e, 0xdf, 0x80, 0xb6, 0x74, 0xa1, 0xd1, 0x5d, 0x09, 0x8d, 0x15, 0xfc, 0xf6, 0xd6, 0xf0, 0xfb, 0x1a, 0xb4, 0xa5, 0x03, 0xa2,
0x40, 0x14, 0x52, 0x9b, 0xc9, 0x09, 0xb6, 0x95, 0x23, 0x52, 0xd9, 0xb1, 0x83, 0xd1, 0x1e, 0xcf, 0x90, 0xda, 0x4c, 0x4e, 0xd0, 0x57, 0x8e, 0x48, 0x65, 0xc7, 0x0e, 0x46, 0x7b, 0x3c, 0x9b, 0x2d,
0x66, 0xcb, 0xcb, 0xc0, 0x63, 0x19, 0x61, 0xb7, 0x52, 0xd9, 0xb1, 0x23, 0xf7, 0x8b, 0x08, 0x24, 0x2f, 0x03, 0x8f, 0x65, 0x84, 0xdd, 0x4a, 0x65, 0xc7, 0x8e, 0xdc, 0x2f, 0x22, 0x90, 0x20, 0x02,
0x88, 0x40, 0x6c, 0x0f, 0x3e, 0x84, 0x66, 0xea, 0xf5, 0x1f, 0x04, 0xa6, 0xbf, 0x96, 0xa0, 0x9d, 0xb1, 0x3d, 0x7c, 0x0f, 0x9a, 0xa9, 0xd7, 0xbf, 0x17, 0x98, 0xfe, 0x5e, 0x82, 0x76, 0x9e, 0x14,
0x27, 0x45, 0x39, 0x78, 0x32, 0x39, 0xc1, 0xc1, 0x15, 0x4b, 0x36, 0x65, 0x39, 0xc1, 0x99, 0xcf, 0xe5, 0xe0, 0xc9, 0xe4, 0x04, 0x07, 0x57, 0x2c, 0xd9, 0x94, 0xe5, 0x04, 0x67, 0x3e, 0x7b, 0x49,
0x5e, 0xd0, 0x99, 0xa7, 0x26, 0x68, 0x58, 0x99, 0x40, 0x6a, 0x5d, 0xdf, 0xe6, 0x6c, 0x91, 0xa0, 0x67, 0x9e, 0x9a, 0xa0, 0x61, 0x65, 0x02, 0xa9, 0x75, 0x7d, 0x9b, 0xb3, 0x45, 0x82, 0xaa, 0x8a,
0xaa, 0x62, 0x65, 0x02, 0xf2, 0x11, 0x80, 0x1b, 0x45, 0x31, 0x53, 0x37, 0xb7, 0x85, 0x94, 0x31, 0x95, 0x09, 0xc8, 0xfb, 0x00, 0x6e, 0x14, 0xc5, 0x4c, 0xdd, 0xdc, 0x16, 0x52, 0xc6, 0x70, 0xac,
0x18, 0xab, 0x1a, 0x73, 0x9c, 0xd4, 0x98, 0xe3, 0x49, 0x52, 0x63, 0x5a, 0x4d, 0xb4, 0xc6, 0x2b, 0x6a, 0xcc, 0x71, 0x52, 0x63, 0x8e, 0x27, 0x49, 0x8d, 0x69, 0x35, 0xd1, 0x1a, 0xaf, 0xf4, 0x2e,
0xbd, 0x0b, 0x35, 0x79, 0x41, 0x93, 0x13, 0x44, 0x5e, 0xc5, 0xd2, 0x3d, 0xf3, 0xcf, 0x50, 0x53, 0xd4, 0xe4, 0x05, 0x4d, 0x4e, 0x10, 0x79, 0x15, 0x4b, 0xf7, 0xcc, 0xbf, 0x40, 0x4d, 0x55, 0x21,
0x55, 0xc8, 0xff, 0x94, 0xe8, 0xef, 0x41, 0x43, 0xcd, 0xed, 0x3a, 0x3a, 0x56, 0xea, 0xd8, 0x3f, 0xff, 0x57, 0xa2, 0xbf, 0x07, 0x0d, 0x35, 0xb7, 0xeb, 0xe8, 0x58, 0xa9, 0x63, 0xff, 0xd8, 0x31,
0x76, 0xcc, 0xef, 0xca, 0xd0, 0xb0, 0x58, 0x14, 0x06, 0x7e, 0xc4, 0x72, 0x55, 0x52, 0xe9, 0xa5, 0xbf, 0x2e, 0x43, 0xc3, 0x62, 0x51, 0x18, 0xf8, 0x11, 0xcb, 0x55, 0x49, 0xa5, 0x6f, 0xad, 0x92,
0x55, 0x52, 0x79, 0x63, 0x95, 0x94, 0xd4, 0x5e, 0x95, 0x5c, 0xed, 0x35, 0x80, 0x06, 0x67, 0x8e, 0xca, 0x1b, 0xab, 0xa4, 0xa4, 0xf6, 0xaa, 0xe4, 0x6a, 0xaf, 0x21, 0x34, 0x38, 0x73, 0x5c, 0xce,
0xcb, 0x99, 0x2d, 0x74, 0x9d, 0x96, 0xf6, 0xa5, 0xee, 0x05, 0xe5, 0x32, 0xbd, 0x47, 0x98, 0x43, 0x6c, 0xa1, 0xeb, 0xb4, 0xb4, 0x2f, 0x75, 0x2f, 0x29, 0x97, 0xe9, 0x3d, 0xc2, 0x1c, 0xd2, 0xb4,
0x9a, 0x56, 0xda, 0x27, 0x4f, 0xf2, 0xc5, 0x85, 0x2a, 0xdb, 0x76, 0x54, 0x71, 0xa1, 0xb6, 0xbb, 0xd2, 0x3e, 0x79, 0x92, 0x2f, 0x2e, 0x54, 0xd9, 0xb6, 0xad, 0x8a, 0x0b, 0xb5, 0xdd, 0x0d, 0xd5,
0xa1, 0xba, 0x78, 0x3f, 0x2b, 0xd2, 0xea, 0x18, 0xcd, 0xf7, 0xf2, 0x03, 0x36, 0x57, 0x69, 0x3f, 0xc5, 0xd3, 0xac, 0x48, 0xab, 0x63, 0x34, 0xdf, 0xcb, 0x0f, 0xd8, 0x5c, 0xa5, 0xfd, 0x60, 0x39,
0x5a, 0xce, 0xfe, 0xae, 0x0c, 0xdb, 0xab, 0x7b, 0xdb, 0x80, 0xc0, 0x1d, 0xa8, 0xaa, 0xdc, 0xa7, 0xfb, 0xeb, 0x32, 0xf4, 0x57, 0xf7, 0xb6, 0x01, 0x81, 0xdb, 0x50, 0x55, 0xb9, 0x4f, 0xc3, 0x57,
0xe1, 0x2b, 0xd6, 0xb2, 0x5e, 0x65, 0x85, 0xe8, 0x7e, 0xb5, 0x4a, 0x1a, 0x2f, 0x87, 0x5e, 0x91, 0xac, 0x65, 0xbd, 0xca, 0x0a, 0xd1, 0xfd, 0x6a, 0x95, 0x34, 0xbe, 0x1d, 0x7a, 0x45, 0x42, 0x79,
0x50, 0xde, 0x86, 0x6d, 0xe9, 0xa2, 0x90, 0x39, 0x59, 0x3d, 0xa7, 0x18, 0xb0, 0xa7, 0xe5, 0x69, 0x13, 0xfa, 0xd2, 0x45, 0x21, 0x73, 0xb2, 0x7a, 0x4e, 0x31, 0x60, 0x4f, 0xcb, 0xd3, 0x8a, 0x6e,
0x45, 0xb7, 0x0b, 0xfd, 0xc4, 0x34, 0xe3, 0x86, 0x5a, 0xc1, 0xf6, 0x28, 0xa1, 0x88, 0xbb, 0x50, 0x17, 0x06, 0x89, 0x69, 0xc6, 0x0d, 0xb5, 0x82, 0xed, 0x51, 0x42, 0x11, 0x77, 0xa1, 0x76, 0x11,
0xbb, 0x08, 0xf8, 0x82, 0x0a, 0x4d, 0x82, 0xba, 0x57, 0x20, 0x39, 0x64, 0xdb, 0x86, 0xc2, 0x64, 0xf0, 0x05, 0x15, 0x9a, 0x04, 0x75, 0xaf, 0x40, 0x72, 0xc8, 0xb6, 0x0d, 0x85, 0xc9, 0x44, 0x28,
0x22, 0x94, 0x6f, 0x16, 0x49, 0x3e, 0xe9, 0x7b, 0x02, 0x59, 0xb0, 0x61, 0x35, 0x92, 0x77, 0x84, 0xdf, 0x2c, 0x92, 0x7c, 0xd2, 0xf7, 0x04, 0xb2, 0x60, 0xc3, 0x6a, 0x24, 0xef, 0x08, 0xf3, 0xb7,
0xf9, 0x5b, 0xe8, 0xad, 0x94, 0x90, 0x1b, 0x1c, 0x99, 0x2d, 0x5f, 0x2e, 0x2c, 0x5f, 0x98, 0xb9, 0xd0, 0x5b, 0x29, 0x21, 0x37, 0x38, 0x32, 0x5b, 0xbe, 0x5c, 0x58, 0xbe, 0x30, 0x73, 0x65, 0x65,
0xb2, 0x32, 0xf3, 0xef, 0xa0, 0xff, 0x39, 0xf5, 0x1d, 0x8f, 0xe9, 0xf9, 0x0f, 0xf8, 0x3c, 0x92, 0xe6, 0xdf, 0xc1, 0xe0, 0x13, 0xea, 0x3b, 0x1e, 0xd3, 0xf3, 0x1f, 0xf0, 0x79, 0x24, 0x93, 0xa1,
0xc9, 0x50, 0xbf, 0x68, 0xa6, 0x3a, 0xfb, 0x74, 0xac, 0xa6, 0x96, 0x1c, 0x3b, 0xe4, 0x11, 0xd4, 0x7e, 0xd1, 0x4c, 0x75, 0xf6, 0xe9, 0x58, 0x4d, 0x2d, 0x39, 0x76, 0xc8, 0x23, 0xa8, 0x73, 0x65,
0xb9, 0xb2, 0xd6, 0x00, 0x68, 0xe5, 0x6a, 0x5c, 0x2b, 0xd1, 0x99, 0xdf, 0x02, 0x29, 0x4c, 0x2d, 0xad, 0x01, 0xd0, 0xca, 0xd5, 0xb8, 0x56, 0xa2, 0x33, 0xbf, 0x02, 0x52, 0x98, 0x5a, 0x3e, 0x66,
0x1f, 0x33, 0x4b, 0x32, 0x92, 0xe8, 0x57, 0xa0, 0xd0, 0x51, 0xd5, 0xce, 0x63, 0xd2, 0x4a, 0xb5, 0x96, 0x64, 0x24, 0xd1, 0xaf, 0x40, 0xa1, 0xa3, 0xaa, 0x9d, 0xc7, 0xa4, 0x95, 0x6a, 0xc9, 0x0e,
0x64, 0x08, 0x15, 0xc6, 0xb9, 0x5e, 0x02, 0x8b, 0xcc, 0xec, 0xe9, 0x68, 0x49, 0x95, 0xf9, 0x33, 0x54, 0x18, 0xe7, 0x7a, 0x09, 0x2c, 0x32, 0xb3, 0xa7, 0xa3, 0x25, 0x55, 0x66, 0x1f, 0xba, 0xc7,
0xe8, 0x9f, 0x87, 0xcc, 0x76, 0xa9, 0x87, 0xcf, 0x3e, 0xb5, 0xc0, 0x43, 0xa8, 0x4a, 0x27, 0x27, 0xbe, 0x2b, 0x5c, 0xea, 0xb9, 0x7f, 0x66, 0x72, 0xe7, 0xe6, 0x53, 0xe8, 0x65, 0x12, 0xb5, 0xa0,
0x84, 0xd1, 0xc4, 0x81, 0xa8, 0x56, 0x72, 0xf3, 0x5b, 0x30, 0xd4, 0xbe, 0x8e, 0x6e, 0xdc, 0x48, 0x9e, 0xa6, 0x74, 0xfb, 0x34, 0x3f, 0x83, 0xc1, 0x79, 0xc8, 0x6c, 0x97, 0x7a, 0xf8, 0x7a, 0x54,
0x30, 0xdf, 0x66, 0x87, 0x97, 0xcc, 0xbe, 0xfa, 0x11, 0x4f, 0x7e, 0x0d, 0xf7, 0x36, 0xad, 0x90, 0xc3, 0x1e, 0x42, 0x55, 0xde, 0x55, 0xc2, 0x3b, 0x4d, 0x1c, 0x88, 0x6a, 0x25, 0x37, 0xbf, 0x02,
0xec, 0xaf, 0x65, 0xcb, 0xde, 0xf4, 0x42, 0xe6, 0x0e, 0x5c, 0xa3, 0x61, 0x01, 0x8a, 0x3e, 0x93, 0x43, 0x1d, 0xef, 0xe8, 0xc6, 0x8d, 0x04, 0xf3, 0x6d, 0x76, 0x78, 0xc9, 0xec, 0xab, 0x1f, 0xd0,
0x12, 0x79, 0x8f, 0x4c, 0x8e, 0x8b, 0x34, 0x1f, 0xeb, 0x5e, 0xe2, 0x8f, 0xca, 0xed, 0xfe, 0xf8, 0x81, 0xd7, 0x70, 0x6f, 0xd3, 0x0a, 0xc9, 0xfe, 0x5a, 0xb6, 0xec, 0x4d, 0x2f, 0x64, 0x0a, 0xc2,
0x5b, 0x09, 0x9a, 0xe7, 0x4c, 0xc4, 0x21, 0x9e, 0xe5, 0x3e, 0x34, 0x67, 0x3c, 0xb8, 0x62, 0x3c, 0x35, 0x1a, 0x16, 0xa0, 0xe8, 0x63, 0x29, 0x91, 0x70, 0x60, 0x72, 0x5c, 0xa4, 0x69, 0x5d, 0xf7,
0x3b, 0x4a, 0x43, 0x09, 0x8e, 0x1d, 0xf2, 0x04, 0x6a, 0x87, 0x81, 0x7f, 0xe1, 0xce, 0xf1, 0x11, 0x12, 0x7f, 0x54, 0x6e, 0xf7, 0xc7, 0x3f, 0x4a, 0xd0, 0x3c, 0x67, 0x22, 0x0e, 0xf1, 0x2c, 0xf7,
0xac, 0x89, 0x21, 0x1d, 0x3b, 0x56, 0x3a, 0x45, 0x0c, 0xda, 0x90, 0x0c, 0xa1, 0xa5, 0x3f, 0x29, 0xa1, 0x39, 0xe3, 0xc1, 0x15, 0xe3, 0xd9, 0x51, 0x1a, 0x4a, 0x70, 0xec, 0x90, 0x27, 0x50, 0x3b,
0x7c, 0xfd, 0xf5, 0xf1, 0xb3, 0xa4, 0x3a, 0xce, 0x89, 0x06, 0x1f, 0x41, 0x2b, 0x37, 0xf0, 0x07, 0x0c, 0xfc, 0x0b, 0x77, 0x8e, 0x6f, 0x69, 0xcd, 0x2f, 0xe9, 0xd8, 0xb1, 0xd2, 0x29, 0x7e, 0xd1,
0xa5, 0xaa, 0xff, 0x07, 0xc0, 0xd5, 0x95, 0x8f, 0xb6, 0xd5, 0x51, 0xf5, 0x48, 0x79, 0xb4, 0x87, 0x86, 0x64, 0x07, 0x5a, 0xfa, 0xcb, 0xc4, 0x17, 0x5f, 0x1c, 0x3f, 0x4f, 0x8a, 0xec, 0x9c, 0x68,
0xd0, 0x94, 0x85, 0x98, 0x52, 0x27, 0x49, 0xb2, 0x94, 0x25, 0x49, 0xf3, 0x11, 0xf4, 0x8f, 0xfd, 0xf8, 0x3e, 0xb4, 0x72, 0x03, 0xbf, 0x57, 0xc6, 0xfb, 0x31, 0x00, 0xae, 0xae, 0x7c, 0xd4, 0xcf,
0x6b, 0xea, 0xb9, 0x0e, 0x15, 0xec, 0x0b, 0xb6, 0x44, 0x17, 0xac, 0xed, 0xc0, 0x3c, 0x87, 0xb6, 0xae, 0xbe, 0xa9, 0x8e, 0xf6, 0x10, 0x9a, 0xb2, 0x9e, 0x53, 0xea, 0x24, 0xd7, 0x96, 0xb2, 0x5c,
0x7e, 0x95, 0xbf, 0xd2, 0x1e, 0xdb, 0x7a, 0x8f, 0xdf, 0x1f, 0x44, 0x6f, 0x43, 0x4f, 0x4f, 0x7a, 0x6b, 0x3e, 0x82, 0xc1, 0xb1, 0x7f, 0x4d, 0x3d, 0xd7, 0xa1, 0x82, 0x7d, 0xca, 0x96, 0xe8, 0x82,
0xe2, 0xea, 0x10, 0x92, 0x35, 0x06, 0x67, 0x17, 0xee, 0x8d, 0x9e, 0x5a, 0xf7, 0xcc, 0xa7, 0xb0, 0xb5, 0x1d, 0x98, 0xe7, 0xd0, 0xd6, 0x8f, 0xfb, 0xef, 0xb4, 0xc7, 0xb6, 0xde, 0xe3, 0x37, 0xc7,
0x9d, 0x33, 0x4d, 0x8f, 0x73, 0xc5, 0x96, 0x51, 0xf2, 0xb5, 0x42, 0xb6, 0x13, 0x0f, 0x94, 0x33, 0xe2, 0x9b, 0xd0, 0xd3, 0x93, 0x9e, 0xb8, 0x3a, 0x12, 0x65, 0xa9, 0xc2, 0xd9, 0x85, 0x7b, 0xa3,
0x0f, 0x98, 0xd0, 0xd5, 0x23, 0x9f, 0x33, 0x71, 0xcb, 0xe9, 0xbe, 0x48, 0x37, 0xf2, 0x9c, 0xe9, 0xa7, 0xd6, 0x3d, 0xf3, 0x19, 0xf4, 0x73, 0xa6, 0xe9, 0x71, 0xae, 0xd8, 0x32, 0x4a, 0x3e, 0x7a,
0xc9, 0x1f, 0x43, 0x95, 0xc9, 0x93, 0xe6, 0xf3, 0x67, 0xde, 0x03, 0x96, 0x52, 0x6f, 0x58, 0xf0, 0xc8, 0x76, 0xe2, 0x81, 0x72, 0xe6, 0x01, 0x13, 0xba, 0x7a, 0xe4, 0x0b, 0x26, 0x6e, 0x39, 0xdd,
0x69, 0xba, 0xe0, 0x59, 0xac, 0x16, 0x7c, 0xc5, 0xb9, 0xcc, 0x37, 0xd3, 0x6d, 0x9c, 0xc5, 0xe2, 0xa7, 0xe9, 0x46, 0x5e, 0x30, 0x3d, 0xf9, 0x63, 0xa8, 0x32, 0x79, 0xd2, 0x7c, 0x1a, 0xce, 0x7b,
0xb6, 0x1b, 0x7d, 0x04, 0x7d, 0x6d, 0xf4, 0x8c, 0x79, 0x4c, 0xb0, 0x5b, 0x8e, 0xf4, 0x18, 0x48, 0xc0, 0x52, 0xea, 0x0d, 0x0b, 0x3e, 0x4b, 0x17, 0x3c, 0x8b, 0xd5, 0x82, 0xdf, 0x71, 0x2e, 0xf3,
0xc1, 0xec, 0xb6, 0xe9, 0x1e, 0x40, 0x63, 0x32, 0x39, 0x49, 0xb5, 0x45, 0x6e, 0x34, 0x3f, 0x86, 0xf5, 0x74, 0x1b, 0x67, 0xb1, 0xb8, 0xed, 0x46, 0x1f, 0xc1, 0x40, 0x1b, 0x3d, 0x67, 0x1e, 0x13,
0xfe, 0x79, 0xec, 0x04, 0x67, 0xdc, 0xbd, 0x76, 0x3d, 0x36, 0x57, 0x8b, 0x25, 0xc5, 0x6f, 0x29, 0xec, 0x96, 0x23, 0x3d, 0x06, 0x52, 0x30, 0xbb, 0x6d, 0xba, 0x07, 0xd0, 0x98, 0x4c, 0x4e, 0x52,
0x57, 0xfc, 0x6e, 0xcc, 0x46, 0xe6, 0x08, 0x48, 0x61, 0x78, 0x7a, 0x6f, 0x51, 0xec, 0x04, 0x3a, 0x6d, 0x91, 0x62, 0xcd, 0x0f, 0x60, 0x70, 0x1e, 0x3b, 0xc1, 0x19, 0x77, 0xaf, 0x5d, 0x8f, 0xcd,
0x84, 0xb1, 0x6d, 0x8e, 0xa0, 0x3d, 0xa1, 0xb2, 0xd8, 0x70, 0x94, 0x8d, 0x01, 0x75, 0xa1, 0xfa, 0xd5, 0x62, 0x49, 0x0d, 0x5d, 0xca, 0xd5, 0xd0, 0x1b, 0x93, 0x9a, 0x39, 0x02, 0x52, 0x18, 0x9e,
0xda, 0x2c, 0xe9, 0x9a, 0xfb, 0xb0, 0x73, 0x48, 0xed, 0x4b, 0xd7, 0x9f, 0x3f, 0x73, 0x23, 0x59, 0xde, 0x5b, 0x14, 0x3b, 0x81, 0x0e, 0x61, 0x6c, 0x9b, 0x23, 0x68, 0x4f, 0xa8, 0xac, 0x59, 0x1c,
0x6d, 0xe9, 0x11, 0x03, 0x68, 0x38, 0x5a, 0xa0, 0x87, 0xa4, 0x7d, 0xf3, 0x5d, 0x78, 0x2d, 0xf7, 0x65, 0x63, 0x40, 0x5d, 0xa8, 0xbe, 0x36, 0x4b, 0xba, 0xe6, 0x3e, 0x6c, 0x1f, 0x52, 0xfb, 0xd2,
0x49, 0xe8, 0x5c, 0xd0, 0xc4, 0x1f, 0x3b, 0x50, 0x8d, 0x64, 0x0f, 0x47, 0x54, 0x2d, 0xd5, 0x31, 0xf5, 0xe7, 0xcf, 0xdd, 0x48, 0x16, 0x6d, 0x7a, 0xc4, 0x10, 0x1a, 0x8e, 0x16, 0xe8, 0x21, 0x69,
0xbf, 0x84, 0x9d, 0x7c, 0x02, 0x96, 0xb5, 0x4f, 0x72, 0x70, 0xac, 0x4a, 0x4a, 0xb9, 0xaa, 0x44, 0xdf, 0x7c, 0x1b, 0x5e, 0xc9, 0x7d, 0x59, 0x3a, 0x17, 0x34, 0xf1, 0xc7, 0x36, 0x54, 0x23, 0xd9,
0xfb, 0xac, 0x9c, 0xe5, 0x93, 0x6d, 0xa8, 0xfc, 0xfa, 0x9b, 0x89, 0x06, 0xbb, 0x6c, 0x9a, 0x7f, 0xc3, 0x11, 0x55, 0x4b, 0x75, 0xcc, 0xcf, 0x60, 0x3b, 0x9f, 0xc7, 0x65, 0x09, 0x95, 0x1c, 0x1c,
0x94, 0xcb, 0x17, 0xe7, 0x53, 0xcb, 0x17, 0x4a, 0x93, 0xd2, 0x2b, 0x95, 0x26, 0xeb, 0x78, 0x7b, 0x8b, 0x9b, 0x52, 0xae, 0xb8, 0xd1, 0x3e, 0x2b, 0x67, 0x69, 0xa9, 0x0f, 0x95, 0x5f, 0x7f, 0x39,
0x17, 0xfa, 0xa7, 0x5e, 0x60, 0x5f, 0x1d, 0xf9, 0x39, 0x6f, 0x18, 0x50, 0x67, 0x7e, 0xde, 0x19, 0xd1, 0x60, 0x97, 0x4d, 0xf3, 0x8f, 0x72, 0xf9, 0xe2, 0x7c, 0x6a, 0xf9, 0x42, 0x85, 0x53, 0xfa,
0x49, 0xd7, 0x7c, 0x0b, 0x7a, 0x27, 0x81, 0x4d, 0xbd, 0xd3, 0x20, 0xf6, 0x45, 0xea, 0x05, 0xfc, 0x4e, 0x15, 0xce, 0x3a, 0xde, 0xde, 0x86, 0xc1, 0xa9, 0x17, 0xd8, 0x57, 0x47, 0x7e, 0xce, 0x1b,
0x46, 0xa7, 0x4d, 0x55, 0xc7, 0x7c, 0x17, 0xba, 0x3a, 0x45, 0xfb, 0x17, 0x41, 0xc2, 0x8c, 0x59, 0x06, 0xd4, 0x99, 0x9f, 0x77, 0x46, 0xd2, 0x35, 0xdf, 0x80, 0xde, 0x49, 0x60, 0x53, 0xef, 0x34,
0x32, 0x2f, 0x15, 0x0b, 0x7d, 0xf3, 0x04, 0x7a, 0x99, 0xb9, 0x9a, 0xf7, 0x2d, 0xa8, 0x29, 0xb5, 0x88, 0x7d, 0x91, 0x7a, 0x01, 0x3f, 0xf5, 0x69, 0x53, 0xd5, 0x31, 0xdf, 0x86, 0xae, 0xce, 0xf4,
0x3e, 0x5b, 0x2f, 0x7d, 0xe9, 0x2a, 0x4b, 0x4b, 0xab, 0x37, 0x1c, 0x6a, 0x01, 0xdd, 0x33, 0xfc, 0xfe, 0x45, 0x90, 0x30, 0x63, 0x56, 0x13, 0x94, 0x8a, 0xef, 0x05, 0xf3, 0x04, 0x7a, 0x99, 0xb9,
0x56, 0x7a, 0xe4, 0x5f, 0xab, 0xc9, 0x8e, 0x81, 0xa8, 0xaf, 0xa7, 0x53, 0xe6, 0x5f, 0xbb, 0x3c, 0x9a, 0xf7, 0x0d, 0xa8, 0x29, 0xb5, 0x3e, 0x5b, 0x2f, 0x7d, 0x30, 0x2b, 0x4b, 0x4b, 0xab, 0x37,
0xf0, 0xb1, 0xb8, 0x2e, 0xe9, 0x12, 0x26, 0x99, 0x38, 0x1d, 0x94, 0x58, 0x58, 0xfd, 0x70, 0x55, 0x1c, 0x6a, 0x01, 0xdd, 0x33, 0xfc, 0xe4, 0x7a, 0xe4, 0x5f, 0xab, 0xc9, 0x8e, 0x81, 0xa8, 0x8f,
0xb4, 0xd1, 0x87, 0x90, 0x7d, 0x89, 0x91, 0xa9, 0x86, 0xb3, 0x45, 0x20, 0xd8, 0x94, 0x3a, 0x4e, 0xb0, 0x53, 0xe6, 0x5f, 0xbb, 0x3c, 0xf0, 0xb1, 0x46, 0x2f, 0xe9, 0x4a, 0x28, 0x99, 0x38, 0x1d,
0x12, 0x2d, 0xa0, 0x44, 0x07, 0x8e, 0xc3, 0xf7, 0xff, 0x53, 0x86, 0xfa, 0xa7, 0x8a, 0xc0, 0xc9, 0x94, 0x58, 0x58, 0x83, 0x70, 0x55, 0xb4, 0xd1, 0x87, 0x90, 0x7d, 0xd0, 0x91, 0xa9, 0x86, 0xb3,
0x27, 0xd0, 0x29, 0xa4, 0x6b, 0xf2, 0x1a, 0x96, 0x75, 0xab, 0xc5, 0xc1, 0xe0, 0xee, 0x9a, 0x58, 0x45, 0x20, 0xd8, 0x94, 0x3a, 0x4e, 0x12, 0x2d, 0xa0, 0x44, 0x07, 0x8e, 0xc3, 0xf7, 0xff, 0x56,
0x9d, 0xeb, 0x3d, 0x68, 0xe7, 0x93, 0x31, 0xc1, 0xc4, 0x8b, 0xdf, 0x85, 0x07, 0x38, 0xd3, 0x7a, 0x81, 0xfa, 0x47, 0x8a, 0xc0, 0xc9, 0x87, 0xd0, 0x29, 0x64, 0x7d, 0xf2, 0x0a, 0x56, 0x87, 0xab,
0xa6, 0x3e, 0x87, 0x9d, 0x4d, 0x69, 0x92, 0x3c, 0xc8, 0x56, 0x58, 0x4f, 0xd1, 0x83, 0xd7, 0x6f, 0x35, 0xc6, 0xf0, 0xee, 0x9a, 0x58, 0x9d, 0xeb, 0x1d, 0x68, 0xe7, 0x93, 0x31, 0xc1, 0xc4, 0x8b,
0xd3, 0x26, 0xe9, 0xb5, 0x7e, 0xe8, 0x31, 0xea, 0xc7, 0x61, 0x7e, 0x07, 0x59, 0x93, 0x3c, 0x81, 0x9f, 0x97, 0x87, 0x38, 0xd3, 0x7a, 0xa6, 0x3e, 0x87, 0xed, 0x4d, 0x69, 0x92, 0x3c, 0xc8, 0x56,
0x4e, 0x21, 0x51, 0xa8, 0x73, 0xae, 0xe5, 0x8e, 0xfc, 0x90, 0xc7, 0x50, 0xc5, 0xe4, 0x44, 0x3a, 0x58, 0x4f, 0xd1, 0xc3, 0x57, 0x6f, 0xd3, 0x26, 0xe9, 0xb5, 0x7e, 0xe8, 0x31, 0xea, 0xc7, 0x61,
0x85, 0x2c, 0x39, 0xe8, 0xa6, 0x5d, 0xb5, 0xf6, 0x10, 0xb6, 0xf0, 0x6b, 0x41, 0x6e, 0x61, 0x1c, 0x7e, 0x07, 0x59, 0x93, 0x3c, 0x81, 0x4e, 0x21, 0x51, 0xa8, 0x73, 0xae, 0xe5, 0x8e, 0xfc, 0x90,
0x91, 0x66, 0xae, 0xfd, 0x7f, 0x95, 0xa0, 0x9e, 0x7c, 0x41, 0x7e, 0x02, 0x5b, 0x32, 0x07, 0x90, 0xc7, 0x50, 0xc5, 0xe4, 0x44, 0x3a, 0x85, 0x2c, 0x39, 0xec, 0xa6, 0x5d, 0xb5, 0xf6, 0xbb, 0x00,
0x3b, 0x39, 0x1a, 0x4d, 0xf2, 0xc7, 0x60, 0x67, 0x45, 0xa8, 0x16, 0x18, 0x43, 0xe5, 0x39, 0x13, 0x59, 0x11, 0x43, 0x88, 0x9a, 0x37, 0x5f, 0xe6, 0x0c, 0xef, 0x14, 0x65, 0x49, 0xa1, 0xb3, 0x85,
0x84, 0xe4, 0x94, 0x3a, 0x19, 0x0c, 0xee, 0x14, 0x65, 0xa9, 0xfd, 0x59, 0x5c, 0xb4, 0xd7, 0x5c, 0xdf, 0x2a, 0x72, 0xfb, 0xc5, 0x85, 0xd2, 0x84, 0xb7, 0xff, 0x9f, 0x12, 0xd4, 0x93, 0xef, 0xd7,
0x5e, 0xb0, 0x4f, 0x59, 0xfa, 0x43, 0xa8, 0x29, 0x96, 0x55, 0x4e, 0x59, 0xe3, 0x67, 0x75, 0xf9, 0x4f, 0x60, 0x4b, 0xa6, 0x0e, 0x72, 0x27, 0xc7, 0xbe, 0x49, 0xda, 0x19, 0x6e, 0xaf, 0x08, 0xd5,
0xeb, 0x7c, 0xbc, 0xff, 0x8f, 0x2d, 0x80, 0xf3, 0x65, 0x24, 0xd8, 0xe2, 0x37, 0x2e, 0x7b, 0x41, 0x02, 0x63, 0xa8, 0xbc, 0x60, 0x42, 0x6d, 0xa8, 0x98, 0x43, 0x86, 0x77, 0x8a, 0xb2, 0xd4, 0xfe,
0x76, 0xa1, 0xa7, 0xbf, 0x89, 0xe0, 0x53, 0x4d, 0xb2, 0x49, 0xce, 0x27, 0x58, 0xf0, 0xa5, 0x64, 0x2c, 0x2e, 0xda, 0xeb, 0x14, 0x50, 0xb0, 0x4f, 0xc9, 0xfd, 0x3d, 0xa8, 0x29, 0x72, 0x56, 0xbe,
0xfd, 0x18, 0x5a, 0xa7, 0xf4, 0xe6, 0xe5, 0x76, 0x9f, 0x40, 0xa7, 0xc0, 0xc1, 0x7a, 0x8b, 0xab, 0x5c, 0xa3, 0x75, 0x85, 0x99, 0x75, 0x1a, 0xdf, 0xff, 0xd7, 0x16, 0xc0, 0xf9, 0x32, 0x12, 0x6c,
0xac, 0xae, 0xb7, 0xb8, 0xce, 0xd6, 0x8f, 0xa1, 0xae, 0x99, 0x39, 0xbf, 0x06, 0xe6, 0xb0, 0x02, 0xf1, 0x1b, 0x97, 0xbd, 0x24, 0xbb, 0xd0, 0xd3, 0x5f, 0x64, 0xf0, 0xa1, 0x28, 0x49, 0x28, 0xe7,
0x63, 0xff, 0x1c, 0x7a, 0x2b, 0xbc, 0x9c, 0xb7, 0xc7, 0xcf, 0x21, 0x1b, 0x79, 0xfb, 0xa9, 0x7c, 0x13, 0x2c, 0x37, 0x53, 0x8e, 0x7f, 0x0c, 0xad, 0x53, 0x7a, 0xf3, 0xed, 0x76, 0x1f, 0x42, 0xa7,
0xed, 0x14, 0xb9, 0x39, 0x3f, 0x50, 0xbf, 0xbc, 0x36, 0x91, 0xf7, 0xf3, 0xe2, 0x3b, 0x09, 0x9f, 0x40, 0xdd, 0x7a, 0x8b, 0xab, 0xc9, 0x40, 0x6f, 0x71, 0x9d, 0xe4, 0x1f, 0x43, 0x5d, 0x13, 0x7a,
0xa8, 0xc6, 0x2a, 0x7d, 0x26, 0xe4, 0x3d, 0xb8, 0xb7, 0x49, 0x93, 0x86, 0x60, 0x9e, 0x41, 0xd7, 0x7e, 0x0d, 0x4c, 0x7d, 0x05, 0xa2, 0xff, 0x39, 0xf4, 0x56, 0xe8, 0x3c, 0x6f, 0x8f, 0x1f, 0x63,
0x42, 0x70, 0x9d, 0x5e, 0xdf, 0x01, 0xc8, 0x48, 0x34, 0x6f, 0x8f, 0xf0, 0x58, 0xe5, 0xd7, 0x0f, 0x36, 0xd2, 0xfd, 0x33, 0xf9, 0xd6, 0x2a, 0x52, 0x7a, 0x7e, 0xa0, 0x7e, 0xf7, 0x6d, 0xe2, 0xfc,
0x00, 0x32, 0x6a, 0x54, 0xa8, 0x2a, 0x32, 0xab, 0x1a, 0xb6, 0x4a, 0x9f, 0xbb, 0xd0, 0x4c, 0xe9, 0x17, 0xc5, 0x57, 0x1a, 0x3e, 0x90, 0x8d, 0x55, 0xd6, 0x4d, 0x38, 0x7f, 0x78, 0x6f, 0x93, 0x26,
0x2c, 0xbf, 0x06, 0x4e, 0x50, 0x64, 0xc7, 0x4f, 0x77, 0x7f, 0x3f, 0x9a, 0xbb, 0xe2, 0x32, 0x9e, 0x8d, 0xdc, 0x3c, 0xf1, 0xae, 0x45, 0xee, 0x3a, 0x2b, 0xbf, 0x05, 0x90, 0x71, 0x6f, 0xde, 0x1e,
0x8d, 0xed, 0x60, 0xb1, 0x77, 0x49, 0xa3, 0x4b, 0xd7, 0x0e, 0x78, 0xb8, 0x77, 0x2d, 0xc1, 0xb4, 0xe1, 0xb1, 0x4a, 0xcb, 0xef, 0x02, 0x64, 0x8c, 0xaa, 0x50, 0x55, 0x24, 0x64, 0x35, 0x6c, 0x95,
0x57, 0xf8, 0xc1, 0x35, 0xab, 0xe1, 0x43, 0xef, 0xfd, 0xff, 0x06, 0x00, 0x00, 0xff, 0xff, 0xbd, 0x75, 0x77, 0xa1, 0x99, 0xb2, 0x60, 0x7e, 0x0d, 0x9c, 0xa0, 0x48, 0xaa, 0x1f, 0xed, 0xfe, 0x7e,
0xc6, 0x6e, 0xfa, 0xf8, 0x1a, 0x00, 0x00, 0x34, 0x77, 0xc5, 0x65, 0x3c, 0x1b, 0xdb, 0xc1, 0x62, 0xef, 0x92, 0x46, 0x97, 0xae, 0x1d, 0xf0,
0x70, 0xef, 0x5a, 0x82, 0x69, 0xaf, 0xf0, 0x7b, 0x6d, 0x56, 0xc3, 0x67, 0xe6, 0xd3, 0xff, 0x05,
0x00, 0x00, 0xff, 0xff, 0xc4, 0xd7, 0xaa, 0x59, 0x76, 0x1b, 0x00, 0x00,
} }
// Reference imports to suppress errors if they are not otherwise used. // Reference imports to suppress errors if they are not otherwise used.
@@ -2927,6 +3001,9 @@ type BackendClient interface {
// broker_id to create a connection back to Vault for use with the Storage // broker_id to create a connection back to Vault for use with the Storage
// and SystemView clients. // and SystemView clients.
Setup(ctx context.Context, in *SetupArgs, opts ...grpc.CallOption) (*SetupReply, error) Setup(ctx context.Context, in *SetupArgs, opts ...grpc.CallOption) (*SetupReply, error)
// Initialize is invoked just after mounting a backend to allow it to
// handle any initialization tasks that need to be performed.
Initialize(ctx context.Context, in *InitializeArgs, opts ...grpc.CallOption) (*InitializeReply, error)
// Type returns the BackendType for the particular backend // Type returns the BackendType for the particular backend
Type(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*TypeReply, error) Type(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*TypeReply, error)
} }
@@ -2993,6 +3070,15 @@ func (c *backendClient) Setup(ctx context.Context, in *SetupArgs, opts ...grpc.C
return out, nil return out, nil
} }
func (c *backendClient) Initialize(ctx context.Context, in *InitializeArgs, opts ...grpc.CallOption) (*InitializeReply, error) {
out := new(InitializeReply)
err := c.cc.Invoke(ctx, "/pb.Backend/Initialize", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *backendClient) Type(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*TypeReply, error) { func (c *backendClient) Type(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*TypeReply, error) {
out := new(TypeReply) out := new(TypeReply)
err := c.cc.Invoke(ctx, "/pb.Backend/Type", in, out, opts...) err := c.cc.Invoke(ctx, "/pb.Backend/Type", in, out, opts...)
@@ -3034,36 +3120,13 @@ type BackendServer interface {
// broker_id to create a connection back to Vault for use with the Storage // broker_id to create a connection back to Vault for use with the Storage
// and SystemView clients. // and SystemView clients.
Setup(context.Context, *SetupArgs) (*SetupReply, error) Setup(context.Context, *SetupArgs) (*SetupReply, error)
// Initialize is invoked just after mounting a backend to allow it to
// handle any initialization tasks that need to be performed.
Initialize(context.Context, *InitializeArgs) (*InitializeReply, error)
// Type returns the BackendType for the particular backend // Type returns the BackendType for the particular backend
Type(context.Context, *Empty) (*TypeReply, error) Type(context.Context, *Empty) (*TypeReply, error)
} }
// UnimplementedBackendServer can be embedded to have forward compatible implementations.
type UnimplementedBackendServer struct {
}
func (*UnimplementedBackendServer) HandleRequest(ctx context.Context, req *HandleRequestArgs) (*HandleRequestReply, error) {
return nil, status.Errorf(codes.Unimplemented, "method HandleRequest not implemented")
}
func (*UnimplementedBackendServer) SpecialPaths(ctx context.Context, req *Empty) (*SpecialPathsReply, error) {
return nil, status.Errorf(codes.Unimplemented, "method SpecialPaths not implemented")
}
func (*UnimplementedBackendServer) HandleExistenceCheck(ctx context.Context, req *HandleExistenceCheckArgs) (*HandleExistenceCheckReply, error) {
return nil, status.Errorf(codes.Unimplemented, "method HandleExistenceCheck not implemented")
}
func (*UnimplementedBackendServer) Cleanup(ctx context.Context, req *Empty) (*Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method Cleanup not implemented")
}
func (*UnimplementedBackendServer) InvalidateKey(ctx context.Context, req *InvalidateKeyArgs) (*Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method InvalidateKey not implemented")
}
func (*UnimplementedBackendServer) Setup(ctx context.Context, req *SetupArgs) (*SetupReply, error) {
return nil, status.Errorf(codes.Unimplemented, "method Setup not implemented")
}
func (*UnimplementedBackendServer) Type(ctx context.Context, req *Empty) (*TypeReply, error) {
return nil, status.Errorf(codes.Unimplemented, "method Type not implemented")
}
func RegisterBackendServer(s *grpc.Server, srv BackendServer) { func RegisterBackendServer(s *grpc.Server, srv BackendServer) {
s.RegisterService(&_Backend_serviceDesc, srv) s.RegisterService(&_Backend_serviceDesc, srv)
} }
@@ -3176,6 +3239,24 @@ func _Backend_Setup_Handler(srv interface{}, ctx context.Context, dec func(inter
return interceptor(ctx, in, info, handler) return interceptor(ctx, in, info, handler)
} }
func _Backend_Initialize_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(InitializeArgs)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(BackendServer).Initialize(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/pb.Backend/Initialize",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(BackendServer).Initialize(ctx, req.(*InitializeArgs))
}
return interceptor(ctx, in, info, handler)
}
func _Backend_Type_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { func _Backend_Type_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(Empty) in := new(Empty)
if err := dec(in); err != nil { if err := dec(in); err != nil {
@@ -3222,6 +3303,10 @@ var _Backend_serviceDesc = grpc.ServiceDesc{
MethodName: "Setup", MethodName: "Setup",
Handler: _Backend_Setup_Handler, Handler: _Backend_Setup_Handler,
}, },
{
MethodName: "Initialize",
Handler: _Backend_Initialize_Handler,
},
{ {
MethodName: "Type", MethodName: "Type",
Handler: _Backend_Type_Handler, Handler: _Backend_Type_Handler,
@@ -3293,23 +3378,6 @@ type StorageServer interface {
Delete(context.Context, *StorageDeleteArgs) (*StorageDeleteReply, error) Delete(context.Context, *StorageDeleteArgs) (*StorageDeleteReply, error)
} }
// UnimplementedStorageServer can be embedded to have forward compatible implementations.
type UnimplementedStorageServer struct {
}
func (*UnimplementedStorageServer) List(ctx context.Context, req *StorageListArgs) (*StorageListReply, error) {
return nil, status.Errorf(codes.Unimplemented, "method List not implemented")
}
func (*UnimplementedStorageServer) Get(ctx context.Context, req *StorageGetArgs) (*StorageGetReply, error) {
return nil, status.Errorf(codes.Unimplemented, "method Get not implemented")
}
func (*UnimplementedStorageServer) Put(ctx context.Context, req *StoragePutArgs) (*StoragePutReply, error) {
return nil, status.Errorf(codes.Unimplemented, "method Put not implemented")
}
func (*UnimplementedStorageServer) Delete(ctx context.Context, req *StorageDeleteArgs) (*StorageDeleteReply, error) {
return nil, status.Errorf(codes.Unimplemented, "method Delete not implemented")
}
func RegisterStorageServer(s *grpc.Server, srv StorageServer) { func RegisterStorageServer(s *grpc.Server, srv StorageServer) {
s.RegisterService(&_Storage_serviceDesc, srv) s.RegisterService(&_Storage_serviceDesc, srv)
} }
@@ -3600,44 +3668,6 @@ type SystemViewServer interface {
PluginEnv(context.Context, *Empty) (*PluginEnvReply, error) PluginEnv(context.Context, *Empty) (*PluginEnvReply, error)
} }
// UnimplementedSystemViewServer can be embedded to have forward compatible implementations.
type UnimplementedSystemViewServer struct {
}
func (*UnimplementedSystemViewServer) DefaultLeaseTTL(ctx context.Context, req *Empty) (*TTLReply, error) {
return nil, status.Errorf(codes.Unimplemented, "method DefaultLeaseTTL not implemented")
}
func (*UnimplementedSystemViewServer) MaxLeaseTTL(ctx context.Context, req *Empty) (*TTLReply, error) {
return nil, status.Errorf(codes.Unimplemented, "method MaxLeaseTTL not implemented")
}
func (*UnimplementedSystemViewServer) SudoPrivilege(ctx context.Context, req *SudoPrivilegeArgs) (*SudoPrivilegeReply, error) {
return nil, status.Errorf(codes.Unimplemented, "method SudoPrivilege not implemented")
}
func (*UnimplementedSystemViewServer) Tainted(ctx context.Context, req *Empty) (*TaintedReply, error) {
return nil, status.Errorf(codes.Unimplemented, "method Tainted not implemented")
}
func (*UnimplementedSystemViewServer) CachingDisabled(ctx context.Context, req *Empty) (*CachingDisabledReply, error) {
return nil, status.Errorf(codes.Unimplemented, "method CachingDisabled not implemented")
}
func (*UnimplementedSystemViewServer) ReplicationState(ctx context.Context, req *Empty) (*ReplicationStateReply, error) {
return nil, status.Errorf(codes.Unimplemented, "method ReplicationState not implemented")
}
func (*UnimplementedSystemViewServer) ResponseWrapData(ctx context.Context, req *ResponseWrapDataArgs) (*ResponseWrapDataReply, error) {
return nil, status.Errorf(codes.Unimplemented, "method ResponseWrapData not implemented")
}
func (*UnimplementedSystemViewServer) MlockEnabled(ctx context.Context, req *Empty) (*MlockEnabledReply, error) {
return nil, status.Errorf(codes.Unimplemented, "method MlockEnabled not implemented")
}
func (*UnimplementedSystemViewServer) LocalMount(ctx context.Context, req *Empty) (*LocalMountReply, error) {
return nil, status.Errorf(codes.Unimplemented, "method LocalMount not implemented")
}
func (*UnimplementedSystemViewServer) EntityInfo(ctx context.Context, req *EntityInfoArgs) (*EntityInfoReply, error) {
return nil, status.Errorf(codes.Unimplemented, "method EntityInfo not implemented")
}
func (*UnimplementedSystemViewServer) PluginEnv(ctx context.Context, req *Empty) (*PluginEnvReply, error) {
return nil, status.Errorf(codes.Unimplemented, "method PluginEnv not implemented")
}
func RegisterSystemViewServer(s *grpc.Server, srv SystemViewServer) { func RegisterSystemViewServer(s *grpc.Server, srv SystemViewServer) {
s.RegisterService(&_SystemView_serviceDesc, srv) s.RegisterService(&_SystemView_serviceDesc, srv)
} }

View File

@@ -355,6 +355,15 @@ message HandleRequestReply {
ProtoError err = 2; ProtoError err = 2;
} }
// InitializeArgs is the args for Initialize method.
message InitializeArgs {
}
// InitializeReply is the reply for Initialize method.
message InitializeReply {
ProtoError err = 1;
}
// SpecialPathsReply is the reply for SpecialPaths method. // SpecialPathsReply is the reply for SpecialPaths method.
message SpecialPathsReply { message SpecialPathsReply {
Paths paths = 1; Paths paths = 1;
@@ -434,6 +443,10 @@ service Backend {
// and SystemView clients. // and SystemView clients.
rpc Setup(SetupArgs) returns (SetupReply); rpc Setup(SetupArgs) returns (SetupReply);
// Initialize is invoked just after mounting a backend to allow it to
// handle any initialization tasks that need to be performed.
rpc Initialize(InitializeArgs) returns (InitializeReply);
// Type returns the BackendType for the particular backend // Type returns the BackendType for the particular backend
rpc Type(Empty) returns (TypeReply); rpc Type(Empty) returns (TypeReply);
} }

View File

@@ -185,6 +185,17 @@ func (c *Core) enableCredentialInternal(ctx context.Context, entry *MountEntry,
return err return err
} }
if !nilMount {
// restore the original readOnlyErr, so we can write to the view in
// Initialize() if necessary
view.setReadOnlyErr(origViewReadOnlyErr)
// initialize, using the core's active context.
err := backend.Initialize(c.activeContext, &logical.InitializationRequest{Storage: view})
if err != nil {
return err
}
}
if c.logger.IsInfo() { if c.logger.IsInfo() {
c.logger.Info("enabled credential backend", "path", entry.Path, "type", entry.Type) c.logger.Info("enabled credential backend", "path", entry.Path, "type", entry.Type)
} }
@@ -678,6 +689,21 @@ func (c *Core) setupCredentials(ctx context.Context) error {
// Populate cache // Populate cache
NamespaceByID(ctx, entry.NamespaceID, c) NamespaceByID(ctx, entry.NamespaceID, c)
// Initialize
if !nilMount {
c.postUnsealFuncs = append(c.postUnsealFuncs, func() {
if backend == nil {
c.logger.Error("skipping initialization on nil backend", "path", entry.Path)
return
}
err := backend.Initialize(ctx, &logical.InitializationRequest{Storage: view})
if err != nil {
c.logger.Error("failed to initialize auth entry", "path", entry.Path, "error", err)
}
})
}
} }
if persistNeeded { if persistNeeded {

View File

@@ -424,3 +424,72 @@ func verifyDefaultAuthTable(t *testing.T, table *MountTable) {
} }
} }
} }
func TestCore_CredentialInitialize(t *testing.T) {
{
backend := &InitializableBackend{
&NoopBackend{
BackendType: logical.TypeCredential,
}, false}
c, _, _ := TestCoreUnsealed(t)
c.credentialBackends["initable"] = func(context.Context, *logical.BackendConfig) (logical.Backend, error) {
return backend, nil
}
me := &MountEntry{
Table: credentialTableType,
Path: "foo/",
Type: "initable",
}
err := c.enableCredential(namespace.RootContext(nil), me)
if err != nil {
t.Fatalf("err: %v", err)
}
if !backend.isInitialized {
t.Fatal("backend is not initialized")
}
}
{
backend := &InitializableBackend{
&NoopBackend{
BackendType: logical.TypeCredential,
}, false}
c, _, _ := TestCoreUnsealed(t)
c.credentialBackends["initable"] = func(context.Context, *logical.BackendConfig) (logical.Backend, error) {
return backend, nil
}
c.auth = &MountTable{
Type: credentialTableType,
Entries: []*MountEntry{
&MountEntry{
Table: credentialTableType,
Path: "foo/",
Type: "initable",
UUID: "abcd",
Accessor: "initable-abcd",
BackendAwareUUID: "abcde",
NamespaceID: namespace.RootNamespaceID,
namespace: namespace.RootNamespace,
},
},
}
err := c.setupCredentials(context.Background())
if err != nil {
t.Fatal(err)
}
// run the postUnseal funcs, so that the backend will be inited
for _, f := range c.postUnsealFuncs {
f()
}
if !backend.isInitialized {
t.Fatal("backend is not initialized")
}
}
}

View File

@@ -511,6 +511,17 @@ func (c *Core) mountInternal(ctx context.Context, entry *MountEntry, updateStora
return err return err
} }
if !nilMount {
// restore the original readOnlyErr, so we can write to the view in
// Initialize() if necessary
view.setReadOnlyErr(origReadOnlyErr)
// initialize, using the core's active context.
err := backend.Initialize(c.activeContext, &logical.InitializationRequest{Storage: view})
if err != nil {
return err
}
}
if c.logger.IsInfo() { if c.logger.IsInfo() {
c.logger.Info("successful mount", "namespace", entry.Namespace().Path, "path", entry.Path, "type", entry.Type) c.logger.Info("successful mount", "namespace", entry.Namespace().Path, "path", entry.Path, "type", entry.Type)
} }
@@ -1131,6 +1142,21 @@ func (c *Core) setupMounts(ctx context.Context) error {
return errLoadMountsFailed return errLoadMountsFailed
} }
// Initialize
if !nilMount {
c.postUnsealFuncs = append(c.postUnsealFuncs, func() {
if backend == nil {
c.logger.Error("skipping initialization on nil backend", "path", entry.Path)
return
}
err := backend.Initialize(ctx, &logical.InitializationRequest{Storage: view})
if err != nil {
c.logger.Error("failed to initialize mount entry", "path", entry.Path, "error", err)
}
})
}
if c.logger.IsInfo() { if c.logger.IsInfo() {
c.logger.Info("successfully mounted backend", "type", entry.Type, "path", entry.Path) c.logger.Info("successfully mounted backend", "type", entry.Type, "path", entry.Path)
} }

View File

@@ -735,3 +735,72 @@ func TestSingletonMountTableFunc(t *testing.T) {
t.Fatal("unexpected entry type for auth") t.Fatal("unexpected entry type for auth")
} }
} }
func TestCore_MountInitialize(t *testing.T) {
{
backend := &InitializableBackend{
&NoopBackend{
BackendType: logical.TypeLogical,
}, false}
c, _, _ := TestCoreUnsealed(t)
c.logicalBackends["initable"] = func(context.Context, *logical.BackendConfig) (logical.Backend, error) {
return backend, nil
}
// Mount the noop backend
me := &MountEntry{
Table: mountTableType,
Path: "foo/",
Type: "initable",
}
if err := c.mount(namespace.RootContext(nil), me); err != nil {
t.Fatalf("err: %v", err)
}
if !backend.isInitialized {
t.Fatal("backend is not initialized")
}
}
{
backend := &InitializableBackend{
&NoopBackend{
BackendType: logical.TypeLogical,
}, false}
c, _, _ := TestCoreUnsealed(t)
c.logicalBackends["initable"] = func(context.Context, *logical.BackendConfig) (logical.Backend, error) {
return backend, nil
}
c.mounts = &MountTable{
Type: mountTableType,
Entries: []*MountEntry{
&MountEntry{
Table: mountTableType,
Path: "foo/",
Type: "initable",
UUID: "abcd",
Accessor: "initable-abcd",
BackendAwareUUID: "abcde",
NamespaceID: namespace.RootNamespaceID,
namespace: namespace.RootNamespace,
},
},
}
err := c.setupMounts(namespace.RootContext(nil))
if err != nil {
t.Fatal(err)
}
// run the postUnseal funcs, so that the backend will be inited
for _, f := range c.postUnsealFuncs {
f()
}
if !backend.isInitialized {
t.Fatal("backend is not initialized")
}
}
}

View File

@@ -2,6 +2,7 @@ package vault
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"sync" "sync"
"time" "time"
@@ -103,7 +104,7 @@ func (n *NoopBackend) Logger() log.Logger {
return log.NewNullLogger() return log.NewNullLogger()
} }
func (n *NoopBackend) Initialize(ctx context.Context) error { func (n *NoopBackend) Initialize(ctx context.Context, req *logical.InitializationRequest) error {
return nil return nil
} }
@@ -113,3 +114,29 @@ func (n *NoopBackend) Type() logical.BackendType {
} }
return n.BackendType 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
}

View File

@@ -717,8 +717,7 @@ func (n *rawHTTP) Cleanup(ctx context.Context) {
// noop // noop
} }
func (n *rawHTTP) Initialize(ctx context.Context) error { func (n *rawHTTP) Initialize(ctx context.Context, req *logical.InitializationRequest) error {
// noop
return nil return nil
} }