d0e2badbae
The result will still pass gofmtcheck and won't trigger additional changes if someone isn't using goimports, but it will avoid the piecemeal imports changes we've been seeing.
249 lines
5.9 KiB
Go
249 lines
5.9 KiB
Go
package plugin
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"net/rpc"
|
|
|
|
log "github.com/hashicorp/go-hclog"
|
|
plugin "github.com/hashicorp/go-plugin"
|
|
"github.com/hashicorp/vault/logical"
|
|
)
|
|
|
|
var (
|
|
ErrClientInMetadataMode = errors.New("plugin client can not perform action while in metadata mode")
|
|
)
|
|
|
|
// backendPluginClient implements logical.Backend and is the
|
|
// go-plugin client.
|
|
type backendPluginClient struct {
|
|
broker *plugin.MuxBroker
|
|
client *rpc.Client
|
|
metadataMode bool
|
|
|
|
system logical.SystemView
|
|
logger log.Logger
|
|
}
|
|
|
|
// HandleRequestArgs is the args for HandleRequest method.
|
|
type HandleRequestArgs struct {
|
|
StorageID uint32
|
|
Request *logical.Request
|
|
}
|
|
|
|
// HandleRequestReply is the reply for HandleRequest method.
|
|
type HandleRequestReply struct {
|
|
Response *logical.Response
|
|
Error error
|
|
}
|
|
|
|
// SpecialPathsReply is the reply for SpecialPaths method.
|
|
type SpecialPathsReply struct {
|
|
Paths *logical.Paths
|
|
}
|
|
|
|
// SystemReply is the reply for System method.
|
|
type SystemReply struct {
|
|
SystemView logical.SystemView
|
|
Error error
|
|
}
|
|
|
|
// HandleExistenceCheckArgs is the args for HandleExistenceCheck method.
|
|
type HandleExistenceCheckArgs struct {
|
|
StorageID uint32
|
|
Request *logical.Request
|
|
}
|
|
|
|
// HandleExistenceCheckReply is the reply for HandleExistenceCheck method.
|
|
type HandleExistenceCheckReply struct {
|
|
CheckFound bool
|
|
Exists bool
|
|
Error error
|
|
}
|
|
|
|
// SetupArgs is the args for Setup method.
|
|
type SetupArgs struct {
|
|
StorageID uint32
|
|
LoggerID uint32
|
|
SysViewID uint32
|
|
Config map[string]string
|
|
BackendUUID string
|
|
}
|
|
|
|
// SetupReply is the reply for Setup method.
|
|
type SetupReply struct {
|
|
Error error
|
|
}
|
|
|
|
// TypeReply is the reply for the Type method.
|
|
type TypeReply struct {
|
|
Type logical.BackendType
|
|
}
|
|
|
|
func (b *backendPluginClient) HandleRequest(ctx context.Context, req *logical.Request) (*logical.Response, error) {
|
|
if b.metadataMode {
|
|
return nil, ErrClientInMetadataMode
|
|
}
|
|
|
|
// Do not send the storage, since go-plugin cannot serialize
|
|
// interfaces. The server will pick up the storage from the shim.
|
|
req.Storage = nil
|
|
args := &HandleRequestArgs{
|
|
Request: req,
|
|
}
|
|
var reply HandleRequestReply
|
|
|
|
if req.Connection != nil {
|
|
oldConnState := req.Connection.ConnState
|
|
req.Connection.ConnState = nil
|
|
defer func() {
|
|
req.Connection.ConnState = oldConnState
|
|
}()
|
|
}
|
|
|
|
err := b.client.Call("Plugin.HandleRequest", args, &reply)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if reply.Error != nil {
|
|
if reply.Error.Error() == logical.ErrUnsupportedOperation.Error() {
|
|
return nil, logical.ErrUnsupportedOperation
|
|
}
|
|
|
|
return reply.Response, reply.Error
|
|
}
|
|
|
|
return reply.Response, nil
|
|
}
|
|
|
|
func (b *backendPluginClient) SpecialPaths() *logical.Paths {
|
|
var reply SpecialPathsReply
|
|
err := b.client.Call("Plugin.SpecialPaths", new(interface{}), &reply)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
|
|
return reply.Paths
|
|
}
|
|
|
|
// System returns vault's system view. The backend client stores the view during
|
|
// Setup, so there is no need to shim the system just to get it back.
|
|
func (b *backendPluginClient) System() logical.SystemView {
|
|
return b.system
|
|
}
|
|
|
|
// Logger returns vault's logger. The backend client stores the logger during
|
|
// Setup, so there is no need to shim the logger just to get it back.
|
|
func (b *backendPluginClient) Logger() log.Logger {
|
|
return b.logger
|
|
}
|
|
|
|
func (b *backendPluginClient) HandleExistenceCheck(ctx context.Context, req *logical.Request) (bool, bool, error) {
|
|
if b.metadataMode {
|
|
return false, false, ErrClientInMetadataMode
|
|
}
|
|
|
|
// Do not send the storage, since go-plugin cannot serialize
|
|
// interfaces. The server will pick up the storage from the shim.
|
|
req.Storage = nil
|
|
args := &HandleExistenceCheckArgs{
|
|
Request: req,
|
|
}
|
|
var reply HandleExistenceCheckReply
|
|
|
|
if req.Connection != nil {
|
|
oldConnState := req.Connection.ConnState
|
|
req.Connection.ConnState = nil
|
|
defer func() {
|
|
req.Connection.ConnState = oldConnState
|
|
}()
|
|
}
|
|
|
|
err := b.client.Call("Plugin.HandleExistenceCheck", args, &reply)
|
|
if err != nil {
|
|
return false, false, err
|
|
}
|
|
if reply.Error != nil {
|
|
// THINKING: Should be be a switch on all error types?
|
|
if reply.Error.Error() == logical.ErrUnsupportedPath.Error() {
|
|
return false, false, logical.ErrUnsupportedPath
|
|
}
|
|
return false, false, reply.Error
|
|
}
|
|
|
|
return reply.CheckFound, reply.Exists, nil
|
|
}
|
|
|
|
func (b *backendPluginClient) Cleanup(ctx context.Context) {
|
|
b.client.Call("Plugin.Cleanup", new(interface{}), &struct{}{})
|
|
}
|
|
|
|
func (b *backendPluginClient) Initialize(ctx context.Context) error {
|
|
if b.metadataMode {
|
|
return ErrClientInMetadataMode
|
|
}
|
|
err := b.client.Call("Plugin.Initialize", new(interface{}), &struct{}{})
|
|
return err
|
|
}
|
|
|
|
func (b *backendPluginClient) InvalidateKey(ctx context.Context, key string) {
|
|
if b.metadataMode {
|
|
return
|
|
}
|
|
b.client.Call("Plugin.InvalidateKey", key, &struct{}{})
|
|
}
|
|
|
|
func (b *backendPluginClient) Setup(ctx context.Context, config *logical.BackendConfig) error {
|
|
// Shim logical.Storage
|
|
storageImpl := config.StorageView
|
|
if b.metadataMode {
|
|
storageImpl = &NOOPStorage{}
|
|
}
|
|
storageID := b.broker.NextId()
|
|
go b.broker.AcceptAndServe(storageID, &StorageServer{
|
|
impl: storageImpl,
|
|
})
|
|
|
|
// Shim logical.SystemView
|
|
sysViewImpl := config.System
|
|
if b.metadataMode {
|
|
sysViewImpl = &logical.StaticSystemView{}
|
|
}
|
|
sysViewID := b.broker.NextId()
|
|
go b.broker.AcceptAndServe(sysViewID, &SystemViewServer{
|
|
impl: sysViewImpl,
|
|
})
|
|
|
|
args := &SetupArgs{
|
|
StorageID: storageID,
|
|
SysViewID: sysViewID,
|
|
Config: config.Config,
|
|
BackendUUID: config.BackendUUID,
|
|
}
|
|
var reply SetupReply
|
|
|
|
err := b.client.Call("Plugin.Setup", args, &reply)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if reply.Error != nil {
|
|
return reply.Error
|
|
}
|
|
|
|
// Set system and logger for getter methods
|
|
b.system = config.System
|
|
b.logger = config.Logger
|
|
|
|
return nil
|
|
}
|
|
|
|
func (b *backendPluginClient) Type() logical.BackendType {
|
|
var reply TypeReply
|
|
err := b.client.Call("Plugin.Type", new(interface{}), &reply)
|
|
if err != nil {
|
|
return logical.TypeUnknown
|
|
}
|
|
|
|
return logical.BackendType(reply.Type)
|
|
}
|