github.com/hashicorp/terraform-plugin-sdk@v1.17.2/plugin/serve.go (about)

     1  package plugin
     2  
     3  import (
     4  	hclog "github.com/hashicorp/go-hclog"
     5  	"github.com/hashicorp/go-plugin"
     6  	grpcplugin "github.com/hashicorp/terraform-plugin-sdk/internal/helper/plugin"
     7  	proto "github.com/hashicorp/terraform-plugin-sdk/internal/tfplugin5"
     8  	"github.com/hashicorp/terraform-plugin-sdk/terraform"
     9  )
    10  
    11  const (
    12  	// The constants below are the names of the plugins that can be dispensed
    13  	// from the plugin server.
    14  	ProviderPluginName = "provider"
    15  
    16  	// DefaultProtocolVersion is the protocol version assumed for legacy clients that don't specify
    17  	// a particular version during their handshake. This is the version used when Terraform 0.10
    18  	// and 0.11 launch plugins that were built with support for both versions 4 and 5, and must
    19  	// stay unchanged at 4 until we intentionally build plugins that are not compatible with 0.10 and
    20  	// 0.11.
    21  	DefaultProtocolVersion = 4
    22  )
    23  
    24  // Handshake is the HandshakeConfig used to configure clients and servers.
    25  var Handshake = plugin.HandshakeConfig{
    26  	// The ProtocolVersion is the version that must match between TF core
    27  	// and TF plugins. This should be bumped whenever a change happens in
    28  	// one or the other that makes it so that they can't safely communicate.
    29  	// This could be adding a new interface value, it could be how
    30  	// helper/schema computes diffs, etc.
    31  	ProtocolVersion: DefaultProtocolVersion,
    32  
    33  	// The magic cookie values should NEVER be changed.
    34  	MagicCookieKey:   "TF_PLUGIN_MAGIC_COOKIE",
    35  	MagicCookieValue: "d602bf8f470bc67ca7faa0386276bbdd4330efaf76d1a219cb4d6991ca9872b2",
    36  }
    37  
    38  type ProviderFunc func() terraform.ResourceProvider
    39  type GRPCProviderFunc func() proto.ProviderServer
    40  
    41  // ServeOpts are the configurations to serve a plugin.
    42  type ServeOpts struct {
    43  	ProviderFunc ProviderFunc
    44  
    45  	// Wrapped versions of the above plugins will automatically shimmed and
    46  	// added to the GRPC functions when possible.
    47  	GRPCProviderFunc GRPCProviderFunc
    48  
    49  	// Logger is the logger that go-plugin will use.
    50  	Logger hclog.Logger
    51  
    52  	// TestConfig should only be set when the provider is being tested; it
    53  	// will opt out of go-plugin's lifecycle management and other features,
    54  	// and will use the supplied configuration options to control the
    55  	// plugin's lifecycle and communicate connection information. See the
    56  	// go-plugin GoDoc for more information.
    57  	TestConfig *plugin.ServeTestConfig
    58  }
    59  
    60  // Serve serves a plugin. This function never returns and should be the final
    61  // function called in the main function of the plugin.
    62  func Serve(opts *ServeOpts) {
    63  	// since the plugins may not yet be aware of the new protocol, we
    64  	// automatically wrap the plugins in the grpc shims.
    65  	if opts.GRPCProviderFunc == nil && opts.ProviderFunc != nil {
    66  		provider := grpcplugin.NewGRPCProviderServerShim(opts.ProviderFunc())
    67  		// this is almost always going to be a *schema.Provider, but check that
    68  		// we got back a valid provider just in case.
    69  		if provider != nil {
    70  			opts.GRPCProviderFunc = func() proto.ProviderServer {
    71  				return provider
    72  			}
    73  		}
    74  	}
    75  
    76  	plugin.Serve(&plugin.ServeConfig{
    77  		HandshakeConfig:  Handshake,
    78  		VersionedPlugins: pluginSet(opts),
    79  		GRPCServer:       plugin.DefaultGRPCServer,
    80  		Logger:           opts.Logger,
    81  		Test:             opts.TestConfig,
    82  	})
    83  }
    84  
    85  // pluginMap returns the legacy map[string]plugin.Plugin to use for configuring
    86  // a plugin server or client.
    87  func legacyPluginMap(opts *ServeOpts) map[string]plugin.Plugin {
    88  	return map[string]plugin.Plugin{
    89  		"provider": &ResourceProviderPlugin{
    90  			ResourceProvider: opts.ProviderFunc,
    91  		},
    92  	}
    93  }
    94  
    95  func pluginSet(opts *ServeOpts) map[int]plugin.PluginSet {
    96  	// Set the legacy netrpc plugins at version 4.
    97  	// The oldest version is returned in when executed by a legacy go-plugin
    98  	// client.
    99  	plugins := map[int]plugin.PluginSet{
   100  		4: legacyPluginMap(opts),
   101  	}
   102  
   103  	// add the new protocol versions if they're configured
   104  	if opts.GRPCProviderFunc != nil {
   105  		plugins[5] = plugin.PluginSet{}
   106  		if opts.GRPCProviderFunc != nil {
   107  			plugins[5]["provider"] = &GRPCProviderPlugin{
   108  				GRPCProvider: opts.GRPCProviderFunc,
   109  			}
   110  		}
   111  	}
   112  	return plugins
   113  }