mirror of
				https://github.com/optim-enterprises-bv/vault.git
				synced 2025-10-31 18:48:08 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			146 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			146 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package plugin
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"errors"
 | |
| 	"fmt"
 | |
| 
 | |
| 	log "github.com/hashicorp/go-hclog"
 | |
| 	"github.com/hashicorp/go-plugin"
 | |
| 	"github.com/hashicorp/vault/sdk/helper/consts"
 | |
| 	"github.com/hashicorp/vault/sdk/helper/pluginutil"
 | |
| 	"github.com/hashicorp/vault/sdk/logical"
 | |
| )
 | |
| 
 | |
| // BackendPluginClient is a wrapper around backendPluginClient
 | |
| // that also contains its plugin.Client instance. It's primarily
 | |
| // used to cleanly kill the client on Cleanup()
 | |
| type BackendPluginClient struct {
 | |
| 	client *plugin.Client
 | |
| 
 | |
| 	logical.Backend
 | |
| }
 | |
| 
 | |
| // Cleanup calls the RPC client's Cleanup() func and also calls
 | |
| // the go-plugin's client Kill() func
 | |
| func (b *BackendPluginClient) Cleanup(ctx context.Context) {
 | |
| 	b.Backend.Cleanup(ctx)
 | |
| 	b.client.Kill()
 | |
| }
 | |
| 
 | |
| // NewBackendWithVersion will return an instance of an RPC-based client implementation of the backend for
 | |
| // external plugins, or a concrete implementation of the backend if it is a builtin backend.
 | |
| // The backend is returned as a logical.Backend interface. The isMetadataMode param determines whether
 | |
| // the plugin should run in metadata mode.
 | |
| func NewBackendWithVersion(ctx context.Context, pluginName string, pluginType consts.PluginType, sys pluginutil.LookRunnerUtil, conf *logical.BackendConfig, isMetadataMode bool, version string) (logical.Backend, error) {
 | |
| 	// Look for plugin in the plugin catalog
 | |
| 	pluginRunner, err := sys.LookupPluginVersion(ctx, pluginName, pluginType, version)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	var backend logical.Backend
 | |
| 	if pluginRunner.Builtin {
 | |
| 		// Plugin is builtin so we can retrieve an instance of the interface
 | |
| 		// from the pluginRunner. Then cast it to logical.Factory.
 | |
| 		rawFactory, err := pluginRunner.BuiltinFactory()
 | |
| 		if err != nil {
 | |
| 			return nil, fmt.Errorf("error getting plugin type: %q", err)
 | |
| 		}
 | |
| 
 | |
| 		if factory, ok := rawFactory.(logical.Factory); !ok {
 | |
| 			return nil, fmt.Errorf("unsupported backend type: %q", pluginName)
 | |
| 		} else {
 | |
| 			if backend, err = factory(ctx, conf); err != nil {
 | |
| 				return nil, err
 | |
| 			}
 | |
| 		}
 | |
| 	} else {
 | |
| 		// create a backendPluginClient instance
 | |
| 		backend, err = NewPluginClient(ctx, sys, pluginRunner, conf.Logger, isMetadataMode)
 | |
| 		if err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return backend, nil
 | |
| }
 | |
| 
 | |
| // NewBackend will return an instance of an RPC-based client implementation of the backend for
 | |
| // external plugins, or a concrete implementation of the backend if it is a builtin backend.
 | |
| // The backend is returned as a logical.Backend interface. The isMetadataMode param determines whether
 | |
| // the plugin should run in metadata mode.
 | |
| func NewBackend(ctx context.Context, pluginName string, pluginType consts.PluginType, sys pluginutil.LookRunnerUtil, conf *logical.BackendConfig, isMetadataMode bool) (logical.Backend, error) {
 | |
| 	return NewBackendWithVersion(ctx, pluginName, pluginType, sys, conf, isMetadataMode, "")
 | |
| }
 | |
| 
 | |
| func NewPluginClient(ctx context.Context, sys pluginutil.RunnerUtil, pluginRunner *pluginutil.PluginRunner, logger log.Logger, isMetadataMode bool) (logical.Backend, error) {
 | |
| 	// pluginMap is the map of plugins we can dispense.
 | |
| 	pluginSet := map[int]plugin.PluginSet{
 | |
| 		// Version 3 used to supports both protocols. We want to keep it around
 | |
| 		// since it's possible old plugins built against this version will still
 | |
| 		// work with gRPC. There is currently no difference between version 3
 | |
| 		// and version 4.
 | |
| 		3: {
 | |
| 			"backend": &GRPCBackendPlugin{
 | |
| 				MetadataMode: isMetadataMode,
 | |
| 			},
 | |
| 		},
 | |
| 		4: {
 | |
| 			"backend": &GRPCBackendPlugin{
 | |
| 				MetadataMode: isMetadataMode,
 | |
| 			},
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	namedLogger := logger.Named(pluginRunner.Name)
 | |
| 
 | |
| 	var client *plugin.Client
 | |
| 	var err error
 | |
| 	if isMetadataMode {
 | |
| 		client, err = pluginRunner.RunMetadataMode(ctx, sys, pluginSet, HandshakeConfig, []string{}, namedLogger)
 | |
| 	} else {
 | |
| 		client, err = pluginRunner.Run(ctx, sys, pluginSet, HandshakeConfig, []string{}, namedLogger)
 | |
| 	}
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	// Connect via RPC
 | |
| 	rpcClient, err := client.Client()
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	// Request the plugin
 | |
| 	raw, err := rpcClient.Dispense("backend")
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	var backend logical.Backend
 | |
| 	var transport string
 | |
| 	// We should have a logical backend type now. This feels like a normal interface
 | |
| 	// implementation but is in fact over an RPC connection.
 | |
| 	switch b := raw.(type) {
 | |
| 	case *backendGRPCPluginClient:
 | |
| 		backend = b
 | |
| 		transport = "gRPC"
 | |
| 	default:
 | |
| 		return nil, errors.New("unsupported plugin client type")
 | |
| 	}
 | |
| 
 | |
| 	// Wrap the backend in a tracing middleware
 | |
| 	if namedLogger.IsTrace() {
 | |
| 		backend = &BackendTracingMiddleware{
 | |
| 			logger: namedLogger.With("transport", transport),
 | |
| 			next:   backend,
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return &BackendPluginClient{
 | |
| 		client:  client,
 | |
| 		Backend: backend,
 | |
| 	}, nil
 | |
| }
 | 
