Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Database gRPC plugins #3666

Merged
merged 22 commits into from
Dec 14, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ proto:
protoc -I helper/forwarding -I vault -I ../../.. helper/forwarding/types.proto --go_out=plugins=grpc:helper/forwarding
protoc -I physical physical/types.proto --go_out=plugins=grpc:physical
protoc -I helper/identity -I ../../.. helper/identity/types.proto --go_out=plugins=grpc:helper/identity
protoc builtin/logical/database/dbplugin/*.proto --go_out=plugins=grpc:.
sed -i -e 's/Idp/IDP/' -e 's/Url/URL/' -e 's/Id/ID/' -e 's/EntityId/EntityID/' -e 's/Api/API/' -e 's/Qr/QR/' -e 's/protobuf:"/sentinel:"" protobuf:"/' helper/identity/types.pb.go helper/storagepacker/types.pb.go
sed -i -e 's/Iv/IV/' -e 's/Hmac/HMAC/' physical/types.pb.go

Expand Down
8 changes: 5 additions & 3 deletions builtin/logical/database/backend.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package database

import (
"context"
"fmt"
"net/rpc"
"strings"
Expand Down Expand Up @@ -87,7 +88,7 @@ func (b *databaseBackend) getDBObj(name string) (dbplugin.Database, bool) {
// This function creates a new db object from the stored configuration and
// caches it in the connections map. The caller of this function needs to hold
// the backend's write lock
func (b *databaseBackend) createDBObj(s logical.Storage, name string) (dbplugin.Database, error) {
func (b *databaseBackend) createDBObj(ctx context.Context, s logical.Storage, name string) (dbplugin.Database, error) {
db, ok := b.connections[name]
if ok {
return db, nil
Expand All @@ -103,7 +104,7 @@ func (b *databaseBackend) createDBObj(s logical.Storage, name string) (dbplugin.
return nil, err
}

err = db.Initialize(config.ConnectionDetails, true)
err = db.Initialize(ctx, config.ConnectionDetails, true)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -170,7 +171,8 @@ func (b *databaseBackend) clearConnection(name string) {

func (b *databaseBackend) closeIfShutdown(name string, err error) {
// Plugin has shutdown, close it so next call can reconnect.
if err == rpc.ErrShutdown {
switch err {
case rpc.ErrShutdown, dbplugin.ErrPluginShutdown:
b.Lock()
b.clearConnection(name)
b.Unlock()
Expand Down
8 changes: 5 additions & 3 deletions builtin/logical/database/backend_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -488,9 +488,11 @@ func TestBackend_roleCrud(t *testing.T) {
RevocationStatements: defaultRevocationSQL,
}

var actual dbplugin.Statements
if err := mapstructure.Decode(resp.Data, &actual); err != nil {
t.Fatal(err)
actual := dbplugin.Statements{
CreationStatements: resp.Data["creation_statements"].(string),
RevocationStatements: resp.Data["revocation_statements"].(string),
RollbackStatements: resp.Data["rollback_statements"].(string),
RenewStatements: resp.Data["renew_statements"].(string),
}

if !reflect.DeepEqual(expected, actual) {
Expand Down
91 changes: 15 additions & 76 deletions builtin/logical/database/dbplugin/client.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
package dbplugin

import (
"fmt"
"net/rpc"
"errors"
"sync"
"time"

"github.com/hashicorp/go-plugin"
"github.com/hashicorp/vault/helper/pluginutil"
Expand All @@ -17,11 +15,11 @@ type DatabasePluginClient struct {
client *plugin.Client
sync.Mutex

*databasePluginRPCClient
Database
}

func (dc *DatabasePluginClient) Close() error {
err := dc.databasePluginRPCClient.Close()
err := dc.Database.Close()
dc.client.Kill()

return err
Expand Down Expand Up @@ -55,79 +53,20 @@ func newPluginClient(sys pluginutil.RunnerUtil, pluginRunner *pluginutil.PluginR

// We should have a database type now. This feels like a normal interface
// implementation but is in fact over an RPC connection.
databaseRPC := raw.(*databasePluginRPCClient)
var db Database
switch raw.(type) {
case *gRPCClient:
db = raw.(*gRPCClient)
case *databasePluginRPCClient:
logger.Warn("database: plugin is using deprecated net RPC transport, recompile plugin to upgrade to gRPC", "plugin", pluginRunner.Name)
db = raw.(*databasePluginRPCClient)
default:
return nil, errors.New("unsupported client type")
}

// Wrap RPC implimentation in DatabasePluginClient
return &DatabasePluginClient{
client: client,
databasePluginRPCClient: databaseRPC,
client: client,
Database: db,
}, nil
}

// ---- RPC client domain ----

// databasePluginRPCClient implements Database and is used on the client to
// make RPC calls to a plugin.
type databasePluginRPCClient struct {
client *rpc.Client
}

func (dr *databasePluginRPCClient) Type() (string, error) {
var dbType string
err := dr.client.Call("Plugin.Type", struct{}{}, &dbType)

return fmt.Sprintf("plugin-%s", dbType), err
}

func (dr *databasePluginRPCClient) CreateUser(statements Statements, usernameConfig UsernameConfig, expiration time.Time) (username string, password string, err error) {
req := CreateUserRequest{
Statements: statements,
UsernameConfig: usernameConfig,
Expiration: expiration,
}

var resp CreateUserResponse
err = dr.client.Call("Plugin.CreateUser", req, &resp)

return resp.Username, resp.Password, err
}

func (dr *databasePluginRPCClient) RenewUser(statements Statements, username string, expiration time.Time) 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{}, verifyConnection bool) error {
req := InitializeRequest{
Config: conf,
VerifyConnection: verifyConnection,
}

err := dr.client.Call("Plugin.Initialize", req, &struct{}{})

return err
}

func (dr *databasePluginRPCClient) Close() error {
err := dr.client.Call("Plugin.Close", struct{}{}, &struct{}{})

return err
}
Loading