aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/github.com/hashicorp/go-plugin/server.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/hashicorp/go-plugin/server.go')
-rw-r--r--vendor/github.com/hashicorp/go-plugin/server.go165
1 files changed, 140 insertions, 25 deletions
diff --git a/vendor/github.com/hashicorp/go-plugin/server.go b/vendor/github.com/hashicorp/go-plugin/server.go
index 1e808b9..fc9f05a 100644
--- a/vendor/github.com/hashicorp/go-plugin/server.go
+++ b/vendor/github.com/hashicorp/go-plugin/server.go
@@ -2,6 +2,7 @@ package plugin
2 2
3import ( 3import (
4 "crypto/tls" 4 "crypto/tls"
5 "crypto/x509"
5 "encoding/base64" 6 "encoding/base64"
6 "errors" 7 "errors"
7 "fmt" 8 "fmt"
@@ -11,7 +12,9 @@ import (
11 "os" 12 "os"
12 "os/signal" 13 "os/signal"
13 "runtime" 14 "runtime"
15 "sort"
14 "strconv" 16 "strconv"
17 "strings"
15 "sync/atomic" 18 "sync/atomic"
16 19
17 "github.com/hashicorp/go-hclog" 20 "github.com/hashicorp/go-hclog"
@@ -36,6 +39,8 @@ type HandshakeConfig struct {
36 // ProtocolVersion is the version that clients must match on to 39 // ProtocolVersion is the version that clients must match on to
37 // agree they can communicate. This should match the ProtocolVersion 40 // agree they can communicate. This should match the ProtocolVersion
38 // set on ClientConfig when using a plugin. 41 // set on ClientConfig when using a plugin.
42 // This field is not required if VersionedPlugins are being used in the
43 // Client or Server configurations.
39 ProtocolVersion uint 44 ProtocolVersion uint
40 45
41 // MagicCookieKey and value are used as a very basic verification 46 // MagicCookieKey and value are used as a very basic verification
@@ -46,6 +51,10 @@ type HandshakeConfig struct {
46 MagicCookieValue string 51 MagicCookieValue string
47} 52}
48 53
54// PluginSet is a set of plugins provided to be registered in the plugin
55// server.
56type PluginSet map[string]Plugin
57
49// ServeConfig configures what sorts of plugins are served. 58// ServeConfig configures what sorts of plugins are served.
50type ServeConfig struct { 59type ServeConfig struct {
51 // HandshakeConfig is the configuration that must match clients. 60 // HandshakeConfig is the configuration that must match clients.
@@ -55,7 +64,13 @@ type ServeConfig struct {
55 TLSProvider func() (*tls.Config, error) 64 TLSProvider func() (*tls.Config, error)
56 65
57 // Plugins are the plugins that are served. 66 // Plugins are the plugins that are served.
58 Plugins map[string]Plugin 67 // The implied version of this PluginSet is the Handshake.ProtocolVersion.
68 Plugins PluginSet
69
70 // VersionedPlugins is a map of PluginSets for specific protocol versions.
71 // These can be used to negotiate a compatible version between client and
72 // server. If this is set, Handshake.ProtocolVersion is not required.
73 VersionedPlugins map[int]PluginSet
59 74
60 // GRPCServer should be non-nil to enable serving the plugins over 75 // GRPCServer should be non-nil to enable serving the plugins over
61 // gRPC. This is a function to create the server when needed with the 76 // gRPC. This is a function to create the server when needed with the
@@ -72,14 +87,83 @@ type ServeConfig struct {
72 Logger hclog.Logger 87 Logger hclog.Logger
73} 88}
74 89
75// Protocol returns the protocol that this server should speak. 90// protocolVersion determines the protocol version and plugin set to be used by
76func (c *ServeConfig) Protocol() Protocol { 91// the server. In the event that there is no suitable version, the last version
77 result := ProtocolNetRPC 92// in the config is returned leaving the client to report the incompatibility.
78 if c.GRPCServer != nil { 93func protocolVersion(opts *ServeConfig) (int, Protocol, PluginSet) {
79 result = ProtocolGRPC 94 protoVersion := int(opts.ProtocolVersion)
95 pluginSet := opts.Plugins
96 protoType := ProtocolNetRPC
97 // Check if the client sent a list of acceptable versions
98 var clientVersions []int
99 if vs := os.Getenv("PLUGIN_PROTOCOL_VERSIONS"); vs != "" {
100 for _, s := range strings.Split(vs, ",") {
101 v, err := strconv.Atoi(s)
102 if err != nil {
103 fmt.Fprintf(os.Stderr, "server sent invalid plugin version %q", s)
104 continue
105 }
106 clientVersions = append(clientVersions, v)
107 }
108 }
109
110 // We want to iterate in reverse order, to ensure we match the newest
111 // compatible plugin version.
112 sort.Sort(sort.Reverse(sort.IntSlice(clientVersions)))
113
114 // set the old un-versioned fields as if they were versioned plugins
115 if opts.VersionedPlugins == nil {
116 opts.VersionedPlugins = make(map[int]PluginSet)
117 }
118
119 if pluginSet != nil {
120 opts.VersionedPlugins[protoVersion] = pluginSet
80 } 121 }
81 122
82 return result 123 // Sort the version to make sure we match the latest first
124 var versions []int
125 for v := range opts.VersionedPlugins {
126 versions = append(versions, v)
127 }
128
129 sort.Sort(sort.Reverse(sort.IntSlice(versions)))
130
131 // See if we have multiple versions of Plugins to choose from
132 for _, version := range versions {
133 // Record each version, since we guarantee that this returns valid
134 // values even if they are not a protocol match.
135 protoVersion = version
136 pluginSet = opts.VersionedPlugins[version]
137
138 // If we have a configured gRPC server we should select a protocol
139 if opts.GRPCServer != nil {
140 // All plugins in a set must use the same transport, so check the first
141 // for the protocol type
142 for _, p := range pluginSet {
143 switch p.(type) {
144 case GRPCPlugin:
145 protoType = ProtocolGRPC
146 default:
147 protoType = ProtocolNetRPC
148 }
149 break
150 }
151 }
152
153 for _, clientVersion := range clientVersions {
154 if clientVersion == protoVersion {
155 return protoVersion, protoType, pluginSet
156 }
157 }
158 }
159
160 // Return the lowest version as the fallback.
161 // Since we iterated over all the versions in reverse order above, these
162 // values are from the lowest version number plugins (which may be from
163 // a combination of the Handshake.ProtocolVersion and ServeConfig.Plugins
164 // fields). This allows serving the oldest version of our plugins to a
165 // legacy client that did not send a PLUGIN_PROTOCOL_VERSIONS list.
166 return protoVersion, protoType, pluginSet
83} 167}
84 168
85// Serve serves the plugins given by ServeConfig. 169// Serve serves the plugins given by ServeConfig.
@@ -107,6 +191,10 @@ func Serve(opts *ServeConfig) {
107 os.Exit(1) 191 os.Exit(1)
108 } 192 }
109 193
194 // negotiate the version and plugins
195 // start with default version in the handshake config
196 protoVersion, protoType, pluginSet := protocolVersion(opts)
197
110 // Logging goes to the original stderr 198 // Logging goes to the original stderr
111 log.SetOutput(os.Stderr) 199 log.SetOutput(os.Stderr)
112 200
@@ -155,12 +243,47 @@ func Serve(opts *ServeConfig) {
155 } 243 }
156 } 244 }
157 245
246 var serverCert string
247 clientCert := os.Getenv("PLUGIN_CLIENT_CERT")
248 // If the client is configured using AutoMTLS, the certificate will be here,
249 // and we need to generate our own in response.
250 if tlsConfig == nil && clientCert != "" {
251 logger.Info("configuring server automatic mTLS")
252 clientCertPool := x509.NewCertPool()
253 if !clientCertPool.AppendCertsFromPEM([]byte(clientCert)) {
254 logger.Error("client cert provided but failed to parse", "cert", clientCert)
255 }
256
257 certPEM, keyPEM, err := generateCert()
258 if err != nil {
259 logger.Error("failed to generate client certificate", "error", err)
260 panic(err)
261 }
262
263 cert, err := tls.X509KeyPair(certPEM, keyPEM)
264 if err != nil {
265 logger.Error("failed to parse client certificate", "error", err)
266 panic(err)
267 }
268
269 tlsConfig = &tls.Config{
270 Certificates: []tls.Certificate{cert},
271 ClientAuth: tls.RequireAndVerifyClientCert,
272 ClientCAs: clientCertPool,
273 MinVersion: tls.VersionTLS12,
274 }
275
276 // We send back the raw leaf cert data for the client rather than the
277 // PEM, since the protocol can't handle newlines.
278 serverCert = base64.RawStdEncoding.EncodeToString(cert.Certificate[0])
279 }
280
158 // Create the channel to tell us when we're done 281 // Create the channel to tell us when we're done
159 doneCh := make(chan struct{}) 282 doneCh := make(chan struct{})
160 283
161 // Build the server type 284 // Build the server type
162 var server ServerProtocol 285 var server ServerProtocol
163 switch opts.Protocol() { 286 switch protoType {
164 case ProtocolNetRPC: 287 case ProtocolNetRPC:
165 // If we have a TLS configuration then we wrap the listener 288 // If we have a TLS configuration then we wrap the listener
166 // ourselves and do it at that level. 289 // ourselves and do it at that level.
@@ -170,7 +293,7 @@ func Serve(opts *ServeConfig) {
170 293
171 // Create the RPC server to dispense 294 // Create the RPC server to dispense
172 server = &RPCServer{ 295 server = &RPCServer{
173 Plugins: opts.Plugins, 296 Plugins: pluginSet,
174 Stdout: stdout_r, 297 Stdout: stdout_r,
175 Stderr: stderr_r, 298 Stderr: stderr_r,
176 DoneCh: doneCh, 299 DoneCh: doneCh,
@@ -179,16 +302,17 @@ func Serve(opts *ServeConfig) {
179 case ProtocolGRPC: 302 case ProtocolGRPC:
180 // Create the gRPC server 303 // Create the gRPC server
181 server = &GRPCServer{ 304 server = &GRPCServer{
182 Plugins: opts.Plugins, 305 Plugins: pluginSet,
183 Server: opts.GRPCServer, 306 Server: opts.GRPCServer,
184 TLS: tlsConfig, 307 TLS: tlsConfig,
185 Stdout: stdout_r, 308 Stdout: stdout_r,
186 Stderr: stderr_r, 309 Stderr: stderr_r,
187 DoneCh: doneCh, 310 DoneCh: doneCh,
311 logger: logger,
188 } 312 }
189 313
190 default: 314 default:
191 panic("unknown server protocol: " + opts.Protocol()) 315 panic("unknown server protocol: " + protoType)
192 } 316 }
193 317
194 // Initialize the servers 318 // Initialize the servers
@@ -197,25 +321,16 @@ func Serve(opts *ServeConfig) {
197 return 321 return
198 } 322 }
199 323
200 // Build the extra configuration
201 extra := ""
202 if v := server.Config(); v != "" {
203 extra = base64.StdEncoding.EncodeToString([]byte(v))
204 }
205 if extra != "" {
206 extra = "|" + extra
207 }
208
209 logger.Debug("plugin address", "network", listener.Addr().Network(), "address", listener.Addr().String()) 324 logger.Debug("plugin address", "network", listener.Addr().Network(), "address", listener.Addr().String())
210 325
211 // Output the address and service name to stdout so that core can bring it up. 326 // Output the address and service name to stdout so that the client can bring it up.
212 fmt.Printf("%d|%d|%s|%s|%s%s\n", 327 fmt.Printf("%d|%d|%s|%s|%s|%s\n",
213 CoreProtocolVersion, 328 CoreProtocolVersion,
214 opts.ProtocolVersion, 329 protoVersion,
215 listener.Addr().Network(), 330 listener.Addr().Network(),
216 listener.Addr().String(), 331 listener.Addr().String(),
217 opts.Protocol(), 332 protoType,
218 extra) 333 serverCert)
219 os.Stdout.Sync() 334 os.Stdout.Sync()
220 335
221 // Eat the interrupts 336 // Eat the interrupts