149 lines
3.7 KiB
Go
149 lines
3.7 KiB
Go
|
package dbplugin
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"net/rpc"
|
||
|
"sync"
|
||
|
"time"
|
||
|
|
||
|
"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
|
||
|
|
||
|
*databasePluginRPCClient
|
||
|
}
|
||
|
|
||
|
func (dc *DatabasePluginClient) Close() error {
|
||
|
err := dc.databasePluginRPCClient.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(sys pluginutil.Wrapper, pluginRunner *pluginutil.PluginRunner) (DatabaseType, error) {
|
||
|
// pluginMap is the map of plugins we can dispense.
|
||
|
var pluginMap = map[string]plugin.Plugin{
|
||
|
"database": new(DatabasePlugin),
|
||
|
}
|
||
|
|
||
|
client, err := pluginRunner.Run(sys, pluginMap, handshakeConfig, []string{})
|
||
|
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 Greeter now! This feels like a normal interface
|
||
|
// implementation but is in fact over an RPC connection.
|
||
|
databaseRPC := raw.(*databasePluginRPCClient)
|
||
|
|
||
|
return &DatabasePluginClient{
|
||
|
client: client,
|
||
|
databasePluginRPCClient: databaseRPC,
|
||
|
}, nil
|
||
|
}
|
||
|
|
||
|
// ---- RPC client domain ----
|
||
|
|
||
|
// databasePluginRPCClient impliments DatabaseType and is used on the client to
|
||
|
// make RPC calls to a plugin.
|
||
|
type databasePluginRPCClient struct {
|
||
|
client *rpc.Client
|
||
|
}
|
||
|
|
||
|
func (dr *databasePluginRPCClient) Type() string {
|
||
|
var dbType string
|
||
|
//TODO: catch error
|
||
|
dr.client.Call("Plugin.Type", struct{}{}, &dbType)
|
||
|
|
||
|
return fmt.Sprintf("plugin-%s", dbType)
|
||
|
}
|
||
|
|
||
|
func (dr *databasePluginRPCClient) CreateUser(statements Statements, username, password, expiration string) error {
|
||
|
req := CreateUserRequest{
|
||
|
Statements: statements,
|
||
|
Username: username,
|
||
|
Password: password,
|
||
|
Expiration: expiration,
|
||
|
}
|
||
|
|
||
|
err := dr.client.Call("Plugin.CreateUser", req, &struct{}{})
|
||
|
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
func (dr *databasePluginRPCClient) RenewUser(statements Statements, username, expiration string) error {
|
||
|
req := RenewUserRequest{
|
||
|
Statements: statements,
|
||
|
Username: username,
|
||
|
Expiration: expiration,
|
||
|
}
|
||
|
|
||
|
err := dr.client.Call("Plugin.RenewUser", req, &struct{}{})
|
||
|
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
func (dr *databasePluginRPCClient) RevokeUser(statements Statements, username string) error {
|
||
|
req := RevokeUserRequest{
|
||
|
Statements: statements,
|
||
|
Username: username,
|
||
|
}
|
||
|
|
||
|
err := dr.client.Call("Plugin.RevokeUser", req, &struct{}{})
|
||
|
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
func (dr *databasePluginRPCClient) Initialize(conf map[string]interface{}) error {
|
||
|
err := dr.client.Call("Plugin.Initialize", conf, &struct{}{})
|
||
|
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
func (dr *databasePluginRPCClient) Close() error {
|
||
|
err := dr.client.Call("Plugin.Close", struct{}{}, &struct{}{})
|
||
|
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
func (dr *databasePluginRPCClient) GenerateUsername(displayName string) (string, error) {
|
||
|
resp := &GenerateUsernameResponse{}
|
||
|
err := dr.client.Call("Plugin.GenerateUsername", displayName, resp)
|
||
|
|
||
|
return resp.Username, err
|
||
|
}
|
||
|
|
||
|
func (dr *databasePluginRPCClient) GeneratePassword() (string, error) {
|
||
|
resp := &GeneratePasswordResponse{}
|
||
|
err := dr.client.Call("Plugin.GeneratePassword", struct{}{}, resp)
|
||
|
|
||
|
return resp.Password, err
|
||
|
}
|
||
|
|
||
|
func (dr *databasePluginRPCClient) GenerateExpiration(duration time.Duration) (string, error) {
|
||
|
resp := &GenerateExpirationResponse{}
|
||
|
err := dr.client.Call("Plugin.GenerateExpiration", duration, resp)
|
||
|
|
||
|
return resp.Expiration, err
|
||
|
}
|