serve the new version 5 grpc plugins

Use the new go-plugin version negotiation to server th appropriate
plugin type when the client requests protocol version 5.
This commit is contained in:
James Bardin 2018-08-14 16:55:20 -04:00 committed by Martin Atkins
parent ff7d51a9b4
commit b403023841
5 changed files with 113 additions and 10 deletions

View File

@ -5,6 +5,7 @@ import (
"errors" "errors"
"sync" "sync"
plugin "github.com/hashicorp/go-plugin"
"github.com/hashicorp/terraform/plugin/proto" "github.com/hashicorp/terraform/plugin/proto"
"github.com/hashicorp/terraform/providers" "github.com/hashicorp/terraform/providers"
"github.com/hashicorp/terraform/version" "github.com/hashicorp/terraform/version"
@ -12,6 +13,25 @@ import (
"google.golang.org/grpc" "google.golang.org/grpc"
) )
// GRPCProviderPlugin implements plugin.GRPCPlugin for the go-plugin package.
type GRPCProviderPlugin struct {
plugin.Plugin
GRPCProvider func() proto.ProviderServer
}
func (p *GRPCProviderPlugin) GRPCClient(ctx context.Context, broker *plugin.GRPCBroker, c *grpc.ClientConn) (interface{}, error) {
return &GRPCProvider{
conn: c,
client: proto.NewProviderClient(c),
ctx: ctx,
}, nil
}
func (p *GRPCProviderPlugin) GRPCServer(broker *plugin.GRPCBroker, s *grpc.Server) error {
proto.RegisterProviderServer(s, p.GRPCProvider())
return nil
}
// GRPCProvider handles the client, or core side of the plugin rpc connection. // GRPCProvider handles the client, or core side of the plugin rpc connection.
// The GRPCProvider methods are mostly a translation layer between the // The GRPCProvider methods are mostly a translation layer between the
// terraform provioders types and the grpc proto types, directly converting // terraform provioders types and the grpc proto types, directly converting

View File

@ -6,6 +6,7 @@ import (
"io" "io"
"sync" "sync"
plugin "github.com/hashicorp/go-plugin"
"github.com/hashicorp/terraform/configs/configschema" "github.com/hashicorp/terraform/configs/configschema"
"github.com/hashicorp/terraform/plugin/proto" "github.com/hashicorp/terraform/plugin/proto"
"github.com/hashicorp/terraform/provisioners" "github.com/hashicorp/terraform/provisioners"
@ -14,6 +15,25 @@ import (
"google.golang.org/grpc" "google.golang.org/grpc"
) )
// GRPCProvisionerPlugin is the plugin.GRPCPlugin implementation.
type GRPCProvisionerPlugin struct {
plugin.Plugin
GRPCProvisioner func() proto.ProvisionerServer
}
func (p *GRPCProvisionerPlugin) GRPCClient(ctx context.Context, broker *plugin.GRPCBroker, c *grpc.ClientConn) (interface{}, error) {
return &GRPCProvisioner{
conn: c,
client: proto.NewProvisionerClient(c),
ctx: ctx,
}, nil
}
func (p *GRPCProvisionerPlugin) GRPCServer(broker *plugin.GRPCBroker, s *grpc.Server) error {
proto.RegisterProvisionerServer(s, p.GRPCProvisioner())
return nil
}
// provisioners.Interface grpc implementation // provisioners.Interface grpc implementation
type GRPCProvisioner struct { type GRPCProvisioner struct {
conn *grpc.ClientConn conn *grpc.ClientConn

View File

@ -9,11 +9,14 @@ import (
// ResourceProviderPlugin is the plugin.Plugin implementation. // ResourceProviderPlugin is the plugin.Plugin implementation.
type ResourceProviderPlugin struct { type ResourceProviderPlugin struct {
F func() terraform.ResourceProvider ResourceProvider func() terraform.ResourceProvider
} }
func (p *ResourceProviderPlugin) Server(b *plugin.MuxBroker) (interface{}, error) { func (p *ResourceProviderPlugin) Server(b *plugin.MuxBroker) (interface{}, error) {
return &ResourceProviderServer{Broker: b, Provider: p.F()}, nil return &ResourceProviderServer{
Broker: b,
Provider: p.ResourceProvider(),
}, nil
} }
func (p *ResourceProviderPlugin) Client( func (p *ResourceProviderPlugin) Client(

View File

@ -10,11 +10,14 @@ import (
// ResourceProvisionerPlugin is the plugin.Plugin implementation. // ResourceProvisionerPlugin is the plugin.Plugin implementation.
type ResourceProvisionerPlugin struct { type ResourceProvisionerPlugin struct {
F func() terraform.ResourceProvisioner ResourceProvisioner func() terraform.ResourceProvisioner
} }
func (p *ResourceProvisionerPlugin) Server(b *plugin.MuxBroker) (interface{}, error) { func (p *ResourceProvisionerPlugin) Server(b *plugin.MuxBroker) (interface{}, error) {
return &ResourceProvisionerServer{Broker: b, Provisioner: p.F()}, nil return &ResourceProvisionerServer{
Broker: b,
Provisioner: p.ResourceProvisioner(),
}, nil
} }
func (p *ResourceProvisionerPlugin) Client( func (p *ResourceProvisionerPlugin) Client(

View File

@ -2,6 +2,8 @@ package plugin
import ( import (
"github.com/hashicorp/go-plugin" "github.com/hashicorp/go-plugin"
grpcplugin "github.com/hashicorp/terraform/helper/plugin"
"github.com/hashicorp/terraform/plugin/proto"
"github.com/hashicorp/terraform/terraform" "github.com/hashicorp/terraform/terraform"
) )
@ -28,27 +30,82 @@ var Handshake = plugin.HandshakeConfig{
type ProviderFunc func() terraform.ResourceProvider type ProviderFunc func() terraform.ResourceProvider
type ProvisionerFunc func() terraform.ResourceProvisioner type ProvisionerFunc func() terraform.ResourceProvisioner
type GRPCProviderFunc func() proto.ProviderServer
type GRPCProvisionerFunc func() proto.ProvisionerServer
// ServeOpts are the configurations to serve a plugin. // ServeOpts are the configurations to serve a plugin.
type ServeOpts struct { type ServeOpts struct {
ProviderFunc ProviderFunc ProviderFunc ProviderFunc
ProvisionerFunc ProvisionerFunc ProvisionerFunc ProvisionerFunc
// Wrapped versions of the above plugins will automatically shimmed and
// added to the GRPC functions when possible.
GRPCProviderFunc GRPCProviderFunc
GRPCProvisionerFunc GRPCProvisionerFunc
} }
// Serve serves a plugin. This function never returns and should be the final // Serve serves a plugin. This function never returns and should be the final
// function called in the main function of the plugin. // function called in the main function of the plugin.
func Serve(opts *ServeOpts) { func Serve(opts *ServeOpts) {
// since the plugins may not yet be aware of the new protocol, we
// automatically wrap the plugins in the grpc shims.
if opts.GRPCProviderFunc == nil && opts.ProviderFunc != nil {
provider := grpcplugin.NewGRPCProviderServerShim(opts.ProviderFunc())
// this is almost always going to be a *schema.Provider, but check that
// we got back a valid provider just in case.
if provider != nil {
opts.GRPCProviderFunc = func() proto.ProviderServer {
return provider
}
}
}
if opts.GRPCProvisionerFunc == nil && opts.ProvisionerFunc != nil {
provider := grpcplugin.NewGRPCProvisionerServerShim(opts.ProvisionerFunc())
if provider != nil {
opts.GRPCProvisionerFunc = func() proto.ProvisionerServer {
return provider
}
}
}
plugin.Serve(&plugin.ServeConfig{ plugin.Serve(&plugin.ServeConfig{
HandshakeConfig: Handshake, HandshakeConfig: Handshake,
Plugins: pluginMap(opts), VersionedPlugins: pluginSet(opts),
GRPCServer: plugin.DefaultGRPCServer,
}) })
} }
// pluginMap returns the map[string]plugin.Plugin to use for configuring a plugin // pluginMap returns the legacy map[string]plugin.Plugin to use for configuring
// server or client. // a plugin server or client.
func pluginMap(opts *ServeOpts) map[string]plugin.Plugin { func pluginMap(opts *ServeOpts) map[string]plugin.Plugin {
return map[string]plugin.Plugin{ return map[string]plugin.Plugin{
"provider": &ResourceProviderPlugin{F: opts.ProviderFunc}, "provider": &ResourceProviderPlugin{
"provisioner": &ResourceProvisionerPlugin{F: opts.ProvisionerFunc}, ResourceProvider: opts.ProviderFunc,
},
"provisioner": &ResourceProvisionerPlugin{
ResourceProvisioner: opts.ProvisionerFunc,
},
} }
} }
func pluginSet(opts *ServeOpts) map[int]plugin.PluginSet {
// Set the legacy netrpc plugins at version 4.
// The oldest version is returned in when executed by a legacy go-plugin
// client.
plugins := map[int]plugin.PluginSet{
4: pluginMap(opts),
}
// add the new protocol versions if they're configured
if opts.GRPCProviderFunc != nil || opts.GRPCProvisionerFunc != nil {
plugins[5] = plugin.PluginSet{
"provider": &GRPCProviderPlugin{
GRPCProvider: opts.GRPCProviderFunc,
},
"provisioner": &GRPCProvisionerPlugin{
GRPCProvisioner: opts.GRPCProvisionerFunc,
},
}
}
return plugins
}