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 }