]>
Commit | Line | Data |
---|---|---|
bae9f6d2 JC |
1 | package plugin |
2 | ||
3 | import ( | |
4 | "github.com/hashicorp/go-plugin" | |
107c1cdb ND |
5 | grpcplugin "github.com/hashicorp/terraform/helper/plugin" |
6 | proto "github.com/hashicorp/terraform/internal/tfplugin5" | |
bae9f6d2 JC |
7 | "github.com/hashicorp/terraform/terraform" |
8 | ) | |
9 | ||
bae9f6d2 | 10 | const ( |
107c1cdb ND |
11 | // The constants below are the names of the plugins that can be dispensed |
12 | // from the plugin server. | |
bae9f6d2 JC |
13 | ProviderPluginName = "provider" |
14 | ProvisionerPluginName = "provisioner" | |
107c1cdb ND |
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 | |
bae9f6d2 JC |
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. | |
107c1cdb | 31 | ProtocolVersion: DefaultProtocolVersion, |
bae9f6d2 JC |
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 ProvisionerFunc func() terraform.ResourceProvisioner | |
107c1cdb ND |
40 | type GRPCProviderFunc func() proto.ProviderServer |
41 | type GRPCProvisionerFunc func() proto.ProvisionerServer | |
bae9f6d2 JC |
42 | |
43 | // ServeOpts are the configurations to serve a plugin. | |
44 | type ServeOpts struct { | |
45 | ProviderFunc ProviderFunc | |
46 | ProvisionerFunc ProvisionerFunc | |
107c1cdb ND |
47 | |
48 | // Wrapped versions of the above plugins will automatically shimmed and | |
49 | // added to the GRPC functions when possible. | |
50 | GRPCProviderFunc GRPCProviderFunc | |
51 | GRPCProvisionerFunc GRPCProvisionerFunc | |
bae9f6d2 JC |
52 | } |
53 | ||
54 | // Serve serves a plugin. This function never returns and should be the final | |
55 | // function called in the main function of the plugin. | |
56 | func Serve(opts *ServeOpts) { | |
107c1cdb ND |
57 | // since the plugins may not yet be aware of the new protocol, we |
58 | // automatically wrap the plugins in the grpc shims. | |
59 | if opts.GRPCProviderFunc == nil && opts.ProviderFunc != nil { | |
60 | provider := grpcplugin.NewGRPCProviderServerShim(opts.ProviderFunc()) | |
61 | // this is almost always going to be a *schema.Provider, but check that | |
62 | // we got back a valid provider just in case. | |
63 | if provider != nil { | |
64 | opts.GRPCProviderFunc = func() proto.ProviderServer { | |
65 | return provider | |
66 | } | |
67 | } | |
68 | } | |
69 | if opts.GRPCProvisionerFunc == nil && opts.ProvisionerFunc != nil { | |
70 | provisioner := grpcplugin.NewGRPCProvisionerServerShim(opts.ProvisionerFunc()) | |
71 | if provisioner != nil { | |
72 | opts.GRPCProvisionerFunc = func() proto.ProvisionerServer { | |
73 | return provisioner | |
74 | } | |
75 | } | |
76 | } | |
77 | ||
bae9f6d2 | 78 | plugin.Serve(&plugin.ServeConfig{ |
107c1cdb ND |
79 | HandshakeConfig: Handshake, |
80 | VersionedPlugins: pluginSet(opts), | |
81 | GRPCServer: plugin.DefaultGRPCServer, | |
bae9f6d2 JC |
82 | }) |
83 | } | |
84 | ||
107c1cdb ND |
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 { | |
bae9f6d2 | 88 | return map[string]plugin.Plugin{ |
107c1cdb ND |
89 | "provider": &ResourceProviderPlugin{ |
90 | ResourceProvider: opts.ProviderFunc, | |
91 | }, | |
92 | "provisioner": &ResourceProvisionerPlugin{ | |
93 | ResourceProvisioner: opts.ProvisionerFunc, | |
94 | }, | |
95 | } | |
96 | } | |
97 | ||
98 | func pluginSet(opts *ServeOpts) map[int]plugin.PluginSet { | |
99 | // Set the legacy netrpc plugins at version 4. | |
100 | // The oldest version is returned in when executed by a legacy go-plugin | |
101 | // client. | |
102 | plugins := map[int]plugin.PluginSet{ | |
103 | 4: legacyPluginMap(opts), | |
104 | } | |
105 | ||
106 | // add the new protocol versions if they're configured | |
107 | if opts.GRPCProviderFunc != nil || opts.GRPCProvisionerFunc != nil { | |
108 | plugins[5] = plugin.PluginSet{} | |
109 | if opts.GRPCProviderFunc != nil { | |
110 | plugins[5]["provider"] = &GRPCProviderPlugin{ | |
111 | GRPCProvider: opts.GRPCProviderFunc, | |
112 | } | |
113 | } | |
114 | if opts.GRPCProvisionerFunc != nil { | |
115 | plugins[5]["provisioner"] = &GRPCProvisionerPlugin{ | |
116 | GRPCProvisioner: opts.GRPCProvisionerFunc, | |
117 | } | |
118 | } | |
bae9f6d2 | 119 | } |
107c1cdb | 120 | return plugins |
bae9f6d2 | 121 | } |