package dbplugin import ( "context" "encoding/json" "errors" "time" "google.golang.org/grpc" "github.com/golang/protobuf/ptypes" "github.com/hashicorp/vault/helper/pluginutil" ) var ( ErrPluginShutdown = errors.New("plugin shutdown") ) // ---- gRPC Server domain ---- type gRPCServer struct { impl Database } func (s *gRPCServer) Type(context.Context, *Empty) (*TypeResponse, error) { t, err := s.impl.Type() if err != nil { return nil, err } return &TypeResponse{ Type: t, }, nil } func (s *gRPCServer) CreateUser(ctx context.Context, req *CreateUserRequest) (*CreateUserResponse, error) { e, err := ptypes.Timestamp(req.Expiration) if err != nil { return nil, err } u, p, err := s.impl.CreateUser(ctx, *req.Statements, *req.UsernameConfig, e) return &CreateUserResponse{ Username: u, Password: p, }, err } func (s *gRPCServer) RenewUser(ctx context.Context, req *RenewUserRequest) (*Empty, error) { e, err := ptypes.Timestamp(req.Expiration) if err != nil { return nil, err } err = s.impl.RenewUser(ctx, *req.Statements, req.Username, e) return &Empty{}, err } func (s *gRPCServer) RevokeUser(ctx context.Context, req *RevokeUserRequest) (*Empty, error) { err := s.impl.RevokeUser(ctx, *req.Statements, req.Username) return &Empty{}, err } func (s *gRPCServer) Initialize(ctx context.Context, req *InitializeRequest) (*Empty, error) { config := map[string]interface{}{} err := json.Unmarshal(req.Config, &config) if err != nil { return nil, err } err = s.impl.Initialize(ctx, config, req.VerifyConnection) return &Empty{}, err } func (s *gRPCServer) Close(_ context.Context, _ *Empty) (*Empty, error) { s.impl.Close() return &Empty{}, nil } // ---- gRPC client domain ---- type gRPCClient struct { client DatabaseClient clientConn *grpc.ClientConn doneCtx context.Context } func (c gRPCClient) Type() (string, error) { resp, err := c.client.Type(c.doneCtx, &Empty{}) if err != nil { return "", err } return resp.Type, err } func (c gRPCClient) CreateUser(ctx context.Context, statements Statements, usernameConfig UsernameConfig, expiration time.Time) (username string, password string, err error) { t, err := ptypes.TimestampProto(expiration) if err != nil { return "", "", err } ctx, cancel := context.WithCancel(ctx) quitCh := pluginutil.CtxCancelIfCanceled(cancel, c.doneCtx) defer close(quitCh) defer cancel() resp, err := c.client.CreateUser(ctx, &CreateUserRequest{ Statements: &statements, UsernameConfig: &usernameConfig, Expiration: t, }) if err != nil { if c.doneCtx.Err() != nil { return "", "", ErrPluginShutdown } return "", "", err } return resp.Username, resp.Password, err } func (c *gRPCClient) RenewUser(ctx context.Context, statements Statements, username string, expiration time.Time) error { t, err := ptypes.TimestampProto(expiration) if err != nil { return err } ctx, cancel := context.WithCancel(ctx) quitCh := pluginutil.CtxCancelIfCanceled(cancel, c.doneCtx) defer close(quitCh) defer cancel() _, err = c.client.RenewUser(ctx, &RenewUserRequest{ Statements: &statements, Username: username, Expiration: t, }) if err != nil { if c.doneCtx.Err() != nil { return ErrPluginShutdown } return err } return nil } func (c *gRPCClient) RevokeUser(ctx context.Context, statements Statements, username string) error { ctx, cancel := context.WithCancel(ctx) quitCh := pluginutil.CtxCancelIfCanceled(cancel, c.doneCtx) defer close(quitCh) defer cancel() _, err := c.client.RevokeUser(ctx, &RevokeUserRequest{ Statements: &statements, Username: username, }) if err != nil { if c.doneCtx.Err() != nil { return ErrPluginShutdown } return err } return nil } func (c *gRPCClient) Initialize(ctx context.Context, config map[string]interface{}, verifyConnection bool) error { configRaw, err := json.Marshal(config) if err != nil { return err } ctx, cancel := context.WithCancel(ctx) quitCh := pluginutil.CtxCancelIfCanceled(cancel, c.doneCtx) defer close(quitCh) defer cancel() _, err = c.client.Initialize(ctx, &InitializeRequest{ Config: configRaw, VerifyConnection: verifyConnection, }) if err != nil { if c.doneCtx.Err() != nil { return ErrPluginShutdown } return err } return nil } func (c *gRPCClient) Close() error { _, err := c.client.Close(c.doneCtx, &Empty{}) return err }