import (
"github.com/hashicorp/go-plugin"
+ grpcplugin "github.com/hashicorp/terraform/helper/plugin"
+ proto "github.com/hashicorp/terraform/internal/tfplugin5"
"github.com/hashicorp/terraform/terraform"
)
-// The constants below are the names of the plugins that can be dispensed
-// from the plugin server.
const (
+ // The constants below are the names of the plugins that can be dispensed
+ // from the plugin server.
ProviderPluginName = "provider"
ProvisionerPluginName = "provisioner"
+
+ // DefaultProtocolVersion is the protocol version assumed for legacy clients that don't specify
+ // a particular version during their handshake. This is the version used when Terraform 0.10
+ // and 0.11 launch plugins that were built with support for both versions 4 and 5, and must
+ // stay unchanged at 4 until we intentionally build plugins that are not compatible with 0.10 and
+ // 0.11.
+ DefaultProtocolVersion = 4
)
// Handshake is the HandshakeConfig used to configure clients and servers.
// one or the other that makes it so that they can't safely communicate.
// This could be adding a new interface value, it could be how
// helper/schema computes diffs, etc.
- ProtocolVersion: 4,
+ ProtocolVersion: DefaultProtocolVersion,
// The magic cookie values should NEVER be changed.
MagicCookieKey: "TF_PLUGIN_MAGIC_COOKIE",
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 {
+ provisioner := grpcplugin.NewGRPCProvisionerServerShim(opts.ProvisionerFunc())
+ if provisioner != nil {
+ opts.GRPCProvisionerFunc = func() proto.ProvisionerServer {
+ return provisioner
+ }
+ }
+ }
+
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.
-func pluginMap(opts *ServeOpts) map[string]plugin.Plugin {
+// pluginMap returns the legacy map[string]plugin.Plugin to use for configuring
+// a plugin server or client.
+func legacyPluginMap(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: legacyPluginMap(opts),
+ }
+
+ // add the new protocol versions if they're configured
+ if opts.GRPCProviderFunc != nil || opts.GRPCProvisionerFunc != nil {
+ plugins[5] = plugin.PluginSet{}
+ if opts.GRPCProviderFunc != nil {
+ plugins[5]["provider"] = &GRPCProviderPlugin{
+ GRPCProvider: opts.GRPCProviderFunc,
+ }
+ }
+ if opts.GRPCProvisionerFunc != nil {
+ plugins[5]["provisioner"] = &GRPCProvisionerPlugin{
+ GRPCProvisioner: opts.GRPCProvisionerFunc,
+ }
+ }
}
+ return plugins
}