]>
Commit | Line | Data |
---|---|---|
1 | package plugin | |
2 | ||
3 | import ( | |
4 | "github.com/hashicorp/go-plugin" | |
5 | grpcplugin "github.com/hashicorp/terraform/helper/plugin" | |
6 | proto "github.com/hashicorp/terraform/internal/tfplugin5" | |
7 | "github.com/hashicorp/terraform/terraform" | |
8 | ) | |
9 | ||
10 | const ( | |
11 | // The constants below are the names of the plugins that can be dispensed | |
12 | // from the plugin server. | |
13 | ProviderPluginName = "provider" | |
14 | ProvisionerPluginName = "provisioner" | |
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 ProvisionerFunc func() terraform.ResourceProvisioner | |
40 | type GRPCProviderFunc func() proto.ProviderServer | |
41 | type GRPCProvisionerFunc func() proto.ProvisionerServer | |
42 | ||
43 | // ServeOpts are the configurations to serve a plugin. | |
44 | type ServeOpts struct { | |
45 | ProviderFunc ProviderFunc | |
46 | ProvisionerFunc ProvisionerFunc | |
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 | |
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) { | |
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 | ||
78 | plugin.Serve(&plugin.ServeConfig{ | |
79 | HandshakeConfig: Handshake, | |
80 | VersionedPlugins: pluginSet(opts), | |
81 | GRPCServer: plugin.DefaultGRPCServer, | |
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 | "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 | } | |
119 | } | |
120 | return plugins | |
121 | } |