mirror of
https://github.com/hashicorp/vault.git
synced 2025-08-20 06:01:10 +02:00
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.
92 lines
2.4 KiB
Go
92 lines
2.4 KiB
Go
package dbplugin
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"sync"
|
|
|
|
log "github.com/hashicorp/go-hclog"
|
|
plugin "github.com/hashicorp/go-plugin"
|
|
"github.com/hashicorp/vault/helper/pluginutil"
|
|
)
|
|
|
|
// DatabasePluginClient embeds a databasePluginRPCClient and wraps it's Close
|
|
// method to also call Kill() on the plugin.Client.
|
|
type DatabasePluginClient struct {
|
|
client *plugin.Client
|
|
sync.Mutex
|
|
|
|
Database
|
|
}
|
|
|
|
// This wraps the Close call and ensures we both close the database connection
|
|
// and kill the plugin.
|
|
func (dc *DatabasePluginClient) Close() error {
|
|
err := dc.Database.Close()
|
|
dc.client.Kill()
|
|
|
|
return err
|
|
}
|
|
|
|
// NewPluginClient returns a databaseRPCClient with a connection to a running
|
|
// plugin. The client is wrapped in a DatabasePluginClient object to ensure the
|
|
// plugin is killed on call of Close().
|
|
func NewPluginClient(ctx context.Context, sys pluginutil.RunnerUtil, pluginRunner *pluginutil.PluginRunner, logger log.Logger, isMetadataMode bool) (Database, error) {
|
|
|
|
// pluginSets is the map of plugins we can dispense.
|
|
pluginSets := map[int]plugin.PluginSet{
|
|
// Version 3 supports both protocols
|
|
3: plugin.PluginSet{
|
|
"database": &DatabasePlugin{
|
|
GRPCDatabasePlugin: new(GRPCDatabasePlugin),
|
|
},
|
|
},
|
|
// Version 4 only supports gRPC
|
|
4: plugin.PluginSet{
|
|
"database": new(GRPCDatabasePlugin),
|
|
},
|
|
}
|
|
|
|
var client *plugin.Client
|
|
var err error
|
|
if isMetadataMode {
|
|
client, err = pluginRunner.RunMetadataMode(ctx, sys, pluginSets, handshakeConfig, []string{}, logger)
|
|
} else {
|
|
client, err = pluginRunner.Run(ctx, sys, pluginSets, handshakeConfig, []string{}, logger)
|
|
}
|
|
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("database")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// We should have a database type now. This feels like a normal interface
|
|
// implementation but is in fact over an RPC connection.
|
|
var db Database
|
|
switch raw.(type) {
|
|
case *gRPCClient:
|
|
db = raw.(*gRPCClient)
|
|
case *databasePluginRPCClient:
|
|
logger.Warn("plugin is using deprecated netRPC transport, recompile plugin to upgrade to gRPC", "plugin", pluginRunner.Name)
|
|
db = raw.(*databasePluginRPCClient)
|
|
default:
|
|
return nil, errors.New("unsupported client type")
|
|
}
|
|
|
|
// Wrap RPC implementation in DatabasePluginClient
|
|
return &DatabasePluginClient{
|
|
client: client,
|
|
Database: db,
|
|
}, nil
|
|
}
|