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"
"sync"
plugin "github.com/hashicorp/go-plugin"
"github.com/hashicorp/terraform/plugin/proto"
"github.com/hashicorp/terraform/providers"
"github.com/hashicorp/terraform/version"
@ -12,6 +13,25 @@ import (
"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.
// The GRPCProvider methods are mostly a translation layer between the
// terraform provioders types and the grpc proto types, directly converting

View File

@ -6,6 +6,7 @@ import (
"io"
"sync"
plugin "github.com/hashicorp/go-plugin"
"github.com/hashicorp/terraform/configs/configschema"
"github.com/hashicorp/terraform/plugin/proto"
"github.com/hashicorp/terraform/provisioners"
@ -14,6 +15,25 @@ import (
"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
type GRPCProvisioner struct {
conn *grpc.ClientConn

View File

@ -9,11 +9,14 @@ import (
// ResourceProviderPlugin is the plugin.Plugin implementation.
type ResourceProviderPlugin struct {
F func() terraform.ResourceProvider
ResourceProvider func() terraform.ResourceProvider
}
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(

View File

@ -10,11 +10,14 @@ import (
// ResourceProvisionerPlugin is the plugin.Plugin implementation.
type ResourceProvisionerPlugin struct {
F func() terraform.ResourceProvisioner
ResourceProvisioner func() terraform.ResourceProvisioner
}
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(

View File

@ -2,6 +2,8 @@ package plugin
import (
"github.com/hashicorp/go-plugin"
grpcplugin "github.com/hashicorp/terraform/helper/plugin"
"github.com/hashicorp/terraform/plugin/proto"
"github.com/hashicorp/terraform/terraform"
)
@ -28,27 +30,82 @@ var Handshake = plugin.HandshakeConfig{
type ProviderFunc func() terraform.ResourceProvider
type ProvisionerFunc func() terraform.ResourceProvisioner
type GRPCProviderFunc func() proto.ProviderServer
type GRPCProvisionerFunc func() proto.ProvisionerServer
// ServeOpts are the configurations to serve a plugin.
type ServeOpts struct {
ProviderFunc ProviderFunc
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
// function called in the main function of the plugin.
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{
HandshakeConfig: Handshake,
Plugins: pluginMap(opts),
HandshakeConfig: Handshake,
VersionedPlugins: pluginSet(opts),
GRPCServer: plugin.DefaultGRPCServer,
})
}
// pluginMap returns the map[string]plugin.Plugin to use for configuring a plugin
// server or client.
// pluginMap returns the legacy map[string]plugin.Plugin to use for configuring
// a plugin server or client.
func pluginMap(opts *ServeOpts) map[string]plugin.Plugin {
return map[string]plugin.Plugin{
"provider": &ResourceProviderPlugin{F: opts.ProviderFunc},
"provisioner": &ResourceProvisionerPlugin{F: opts.ProvisionerFunc},
"provider": &ResourceProviderPlugin{
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
}