2016-01-25 03:10:52 +01:00
|
|
|
package plugin
|
|
|
|
|
|
|
|
import (
|
|
|
|
"github.com/hashicorp/go-plugin"
|
2018-08-14 22:55:20 +02:00
|
|
|
grpcplugin "github.com/hashicorp/terraform/helper/plugin"
|
2018-11-19 18:39:16 +01:00
|
|
|
proto "github.com/hashicorp/terraform/internal/tfplugin5"
|
2016-01-25 03:10:52 +01:00
|
|
|
"github.com/hashicorp/terraform/terraform"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2019-01-16 20:00:08 +01:00
|
|
|
// The constants below are the names of the plugins that can be dispensed
|
|
|
|
// from the plugin server.
|
2016-01-25 03:10:52 +01:00
|
|
|
ProviderPluginName = "provider"
|
|
|
|
ProvisionerPluginName = "provisioner"
|
2019-01-16 20:00:08 +01:00
|
|
|
|
|
|
|
// 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
|
2016-01-25 03:10:52 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
// Handshake is the HandshakeConfig used to configure clients and servers.
|
|
|
|
var Handshake = plugin.HandshakeConfig{
|
2016-11-17 19:03:09 +01:00
|
|
|
// The ProtocolVersion is the version that must match between TF core
|
|
|
|
// and TF plugins. This should be bumped whenever a change happens in
|
|
|
|
// 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.
|
2019-01-16 20:00:08 +01:00
|
|
|
ProtocolVersion: DefaultProtocolVersion,
|
2016-11-17 19:03:09 +01:00
|
|
|
|
|
|
|
// The magic cookie values should NEVER be changed.
|
2016-01-25 03:10:52 +01:00
|
|
|
MagicCookieKey: "TF_PLUGIN_MAGIC_COOKIE",
|
|
|
|
MagicCookieValue: "d602bf8f470bc67ca7faa0386276bbdd4330efaf76d1a219cb4d6991ca9872b2",
|
|
|
|
}
|
|
|
|
|
|
|
|
type ProviderFunc func() terraform.ResourceProvider
|
|
|
|
type ProvisionerFunc func() terraform.ResourceProvisioner
|
2018-08-14 22:55:20 +02:00
|
|
|
type GRPCProviderFunc func() proto.ProviderServer
|
|
|
|
type GRPCProvisionerFunc func() proto.ProvisionerServer
|
2016-01-25 03:10:52 +01:00
|
|
|
|
|
|
|
// ServeOpts are the configurations to serve a plugin.
|
|
|
|
type ServeOpts struct {
|
|
|
|
ProviderFunc ProviderFunc
|
|
|
|
ProvisionerFunc ProvisionerFunc
|
2018-08-14 22:55:20 +02:00
|
|
|
|
|
|
|
// Wrapped versions of the above plugins will automatically shimmed and
|
|
|
|
// added to the GRPC functions when possible.
|
|
|
|
GRPCProviderFunc GRPCProviderFunc
|
|
|
|
GRPCProvisionerFunc GRPCProvisionerFunc
|
2016-01-25 03:10:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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) {
|
2018-08-14 22:55:20 +02:00
|
|
|
// 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 {
|
2018-08-25 01:53:05 +02:00
|
|
|
provisioner := grpcplugin.NewGRPCProvisionerServerShim(opts.ProvisionerFunc())
|
|
|
|
if provisioner != nil {
|
2018-08-14 22:55:20 +02:00
|
|
|
opts.GRPCProvisionerFunc = func() proto.ProvisionerServer {
|
2018-08-25 01:53:05 +02:00
|
|
|
return provisioner
|
2018-08-14 22:55:20 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-25 03:10:52 +01:00
|
|
|
plugin.Serve(&plugin.ServeConfig{
|
2018-08-14 22:55:20 +02:00
|
|
|
HandshakeConfig: Handshake,
|
|
|
|
VersionedPlugins: pluginSet(opts),
|
|
|
|
GRPCServer: plugin.DefaultGRPCServer,
|
2016-01-25 03:10:52 +01:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2018-08-14 22:55:20 +02:00
|
|
|
// pluginMap returns the legacy map[string]plugin.Plugin to use for configuring
|
|
|
|
// a plugin server or client.
|
2018-08-25 01:53:05 +02:00
|
|
|
func legacyPluginMap(opts *ServeOpts) map[string]plugin.Plugin {
|
2016-01-25 03:10:52 +01:00
|
|
|
return map[string]plugin.Plugin{
|
2018-08-14 22:55:20 +02:00
|
|
|
"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{
|
2018-08-25 01:53:05 +02:00
|
|
|
4: legacyPluginMap(opts),
|
2018-08-14 22:55:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// add the new protocol versions if they're configured
|
|
|
|
if opts.GRPCProviderFunc != nil || opts.GRPCProvisionerFunc != nil {
|
2018-08-25 01:53:05 +02:00
|
|
|
plugins[5] = plugin.PluginSet{}
|
|
|
|
if opts.GRPCProviderFunc != nil {
|
|
|
|
plugins[5]["provider"] = &GRPCProviderPlugin{
|
2018-08-14 22:55:20 +02:00
|
|
|
GRPCProvider: opts.GRPCProviderFunc,
|
2018-08-25 01:53:05 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if opts.GRPCProvisionerFunc != nil {
|
|
|
|
plugins[5]["provisioner"] = &GRPCProvisionerPlugin{
|
2018-08-14 22:55:20 +02:00
|
|
|
GRPCProvisioner: opts.GRPCProvisionerFunc,
|
2018-08-25 01:53:05 +02:00
|
|
|
}
|
2018-08-14 22:55:20 +02:00
|
|
|
}
|
2016-01-25 03:10:52 +01:00
|
|
|
}
|
2018-08-14 22:55:20 +02:00
|
|
|
return plugins
|
2016-01-25 03:10:52 +01:00
|
|
|
}
|