diff options
author | Nathan Dench <ndenc2@gmail.com> | 2019-05-24 15:16:44 +1000 |
---|---|---|
committer | Nathan Dench <ndenc2@gmail.com> | 2019-05-24 15:16:44 +1000 |
commit | 107c1cdb09c575aa2f61d97f48d8587eb6bada4c (patch) | |
tree | ca7d008643efc555c388baeaf1d986e0b6b3e28c /vendor/github.com/hashicorp/go-plugin | |
parent | 844b5a68d8af4791755b8f0ad293cc99f5959183 (diff) | |
download | terraform-provider-statuscake-107c1cdb09c575aa2f61d97f48d8587eb6bada4c.tar.gz terraform-provider-statuscake-107c1cdb09c575aa2f61d97f48d8587eb6bada4c.tar.zst terraform-provider-statuscake-107c1cdb09c575aa2f61d97f48d8587eb6bada4c.zip |
Upgrade to 0.12
Diffstat (limited to 'vendor/github.com/hashicorp/go-plugin')
17 files changed, 963 insertions, 270 deletions
diff --git a/vendor/github.com/hashicorp/go-plugin/README.md b/vendor/github.com/hashicorp/go-plugin/README.md index e4558db..fe305ad 100644 --- a/vendor/github.com/hashicorp/go-plugin/README.md +++ b/vendor/github.com/hashicorp/go-plugin/README.md | |||
@@ -109,7 +109,7 @@ high-level steps that must be done. Examples are available in the | |||
109 | 1. Choose the interface(s) you want to expose for plugins. | 109 | 1. Choose the interface(s) you want to expose for plugins. |
110 | 110 | ||
111 | 2. For each interface, implement an implementation of that interface | 111 | 2. For each interface, implement an implementation of that interface |
112 | that communicates over a `net/rpc` connection or other a | 112 | that communicates over a `net/rpc` connection or over a |
113 | [gRPC](http://www.grpc.io) connection or both. You'll have to implement | 113 | [gRPC](http://www.grpc.io) connection or both. You'll have to implement |
114 | both a client and server implementation. | 114 | both a client and server implementation. |
115 | 115 | ||
@@ -150,19 +150,19 @@ user experience. | |||
150 | 150 | ||
151 | When we started using plugins (late 2012, early 2013), plugins over RPC | 151 | When we started using plugins (late 2012, early 2013), plugins over RPC |
152 | were the only option since Go didn't support dynamic library loading. Today, | 152 | were the only option since Go didn't support dynamic library loading. Today, |
153 | Go still doesn't support dynamic library loading, but they do intend to. | 153 | Go supports the [plugin](https://golang.org/pkg/plugin/) standard library with |
154 | Since 2012, our plugin system has stabilized from millions of users using it, | 154 | a number of limitations. Since 2012, our plugin system has stabilized |
155 | and has many benefits we've come to value greatly. | 155 | from tens of millions of users using it, and has many benefits we've come to |
156 | 156 | value greatly. | |
157 | For example, we intend to use this plugin system in | 157 | |
158 | [Vault](https://www.vaultproject.io), and dynamic library loading will | 158 | For example, we use this plugin system in |
159 | simply never be acceptable in Vault for security reasons. That is an extreme | 159 | [Vault](https://www.vaultproject.io) where dynamic library loading is |
160 | not acceptable for security reasons. That is an extreme | ||
160 | example, but we believe our library system has more upsides than downsides | 161 | example, but we believe our library system has more upsides than downsides |
161 | over dynamic library loading and since we've had it built and tested for years, | 162 | over dynamic library loading and since we've had it built and tested for years, |
162 | we'll likely continue to use it. | 163 | we'll continue to use it. |
163 | 164 | ||
164 | Shared libraries have one major advantage over our system which is much | 165 | Shared libraries have one major advantage over our system which is much |
165 | higher performance. In real world scenarios across our various tools, | 166 | higher performance. In real world scenarios across our various tools, |
166 | we've never required any more performance out of our plugin system and it | 167 | we've never required any more performance out of our plugin system and it |
167 | has seen very high throughput, so this isn't a concern for us at the moment. | 168 | has seen very high throughput, so this isn't a concern for us at the moment. |
168 | |||
diff --git a/vendor/github.com/hashicorp/go-plugin/client.go b/vendor/github.com/hashicorp/go-plugin/client.go index b3e3b78..679e10a 100644 --- a/vendor/github.com/hashicorp/go-plugin/client.go +++ b/vendor/github.com/hashicorp/go-plugin/client.go | |||
@@ -5,12 +5,13 @@ import ( | |||
5 | "context" | 5 | "context" |
6 | "crypto/subtle" | 6 | "crypto/subtle" |
7 | "crypto/tls" | 7 | "crypto/tls" |
8 | "crypto/x509" | ||
9 | "encoding/base64" | ||
8 | "errors" | 10 | "errors" |
9 | "fmt" | 11 | "fmt" |
10 | "hash" | 12 | "hash" |
11 | "io" | 13 | "io" |
12 | "io/ioutil" | 14 | "io/ioutil" |
13 | "log" | ||
14 | "net" | 15 | "net" |
15 | "os" | 16 | "os" |
16 | "os/exec" | 17 | "os/exec" |
@@ -20,7 +21,6 @@ import ( | |||
20 | "sync" | 21 | "sync" |
21 | "sync/atomic" | 22 | "sync/atomic" |
22 | "time" | 23 | "time" |
23 | "unicode" | ||
24 | 24 | ||
25 | hclog "github.com/hashicorp/go-hclog" | 25 | hclog "github.com/hashicorp/go-hclog" |
26 | ) | 26 | ) |
@@ -71,16 +71,31 @@ var ( | |||
71 | // | 71 | // |
72 | // See NewClient and ClientConfig for using a Client. | 72 | // See NewClient and ClientConfig for using a Client. |
73 | type Client struct { | 73 | type Client struct { |
74 | config *ClientConfig | 74 | config *ClientConfig |
75 | exited bool | 75 | exited bool |
76 | doneLogging chan struct{} | 76 | l sync.Mutex |
77 | l sync.Mutex | 77 | address net.Addr |
78 | address net.Addr | 78 | process *os.Process |
79 | process *os.Process | 79 | client ClientProtocol |
80 | client ClientProtocol | 80 | protocol Protocol |
81 | protocol Protocol | 81 | logger hclog.Logger |
82 | logger hclog.Logger | 82 | doneCtx context.Context |
83 | doneCtx context.Context | 83 | ctxCancel context.CancelFunc |
84 | negotiatedVersion int | ||
85 | |||
86 | // clientWaitGroup is used to manage the lifecycle of the plugin management | ||
87 | // goroutines. | ||
88 | clientWaitGroup sync.WaitGroup | ||
89 | |||
90 | // processKilled is used for testing only, to flag when the process was | ||
91 | // forcefully killed. | ||
92 | processKilled bool | ||
93 | } | ||
94 | |||
95 | // NegotiatedVersion returns the protocol version negotiated with the server. | ||
96 | // This is only valid after Start() is called. | ||
97 | func (c *Client) NegotiatedVersion() int { | ||
98 | return c.negotiatedVersion | ||
84 | } | 99 | } |
85 | 100 | ||
86 | // ClientConfig is the configuration used to initialize a new | 101 | // ClientConfig is the configuration used to initialize a new |
@@ -91,7 +106,13 @@ type ClientConfig struct { | |||
91 | HandshakeConfig | 106 | HandshakeConfig |
92 | 107 | ||
93 | // Plugins are the plugins that can be consumed. | 108 | // Plugins are the plugins that can be consumed. |
94 | Plugins map[string]Plugin | 109 | // The implied version of this PluginSet is the Handshake.ProtocolVersion. |
110 | Plugins PluginSet | ||
111 | |||
112 | // VersionedPlugins is a map of PluginSets for specific protocol versions. | ||
113 | // These can be used to negotiate a compatible version between client and | ||
114 | // server. If this is set, Handshake.ProtocolVersion is not required. | ||
115 | VersionedPlugins map[int]PluginSet | ||
95 | 116 | ||
96 | // One of the following must be set, but not both. | 117 | // One of the following must be set, but not both. |
97 | // | 118 | // |
@@ -158,6 +179,29 @@ type ClientConfig struct { | |||
158 | // Logger is the logger that the client will used. If none is provided, | 179 | // Logger is the logger that the client will used. If none is provided, |
159 | // it will default to hclog's default logger. | 180 | // it will default to hclog's default logger. |
160 | Logger hclog.Logger | 181 | Logger hclog.Logger |
182 | |||
183 | // AutoMTLS has the client and server automatically negotiate mTLS for | ||
184 | // transport authentication. This ensures that only the original client will | ||
185 | // be allowed to connect to the server, and all other connections will be | ||
186 | // rejected. The client will also refuse to connect to any server that isn't | ||
187 | // the original instance started by the client. | ||
188 | // | ||
189 | // In this mode of operation, the client generates a one-time use tls | ||
190 | // certificate, sends the public x.509 certificate to the new server, and | ||
191 | // the server generates a one-time use tls certificate, and sends the public | ||
192 | // x.509 certificate back to the client. These are used to authenticate all | ||
193 | // rpc connections between the client and server. | ||
194 | // | ||
195 | // Setting AutoMTLS to true implies that the server must support the | ||
196 | // protocol, and correctly negotiate the tls certificates, or a connection | ||
197 | // failure will result. | ||
198 | // | ||
199 | // The client should not set TLSConfig, nor should the server set a | ||
200 | // TLSProvider, because AutoMTLS implies that a new certificate and tls | ||
201 | // configuration will be generated at startup. | ||
202 | // | ||
203 | // You cannot Reattach to a server with this option enabled. | ||
204 | AutoMTLS bool | ||
161 | } | 205 | } |
162 | 206 | ||
163 | // ReattachConfig is used to configure a client to reattach to an | 207 | // ReattachConfig is used to configure a client to reattach to an |
@@ -234,7 +278,6 @@ func CleanupClients() { | |||
234 | } | 278 | } |
235 | managedClientsLock.Unlock() | 279 | managedClientsLock.Unlock() |
236 | 280 | ||
237 | log.Println("[DEBUG] plugin: waiting for all plugin processes to complete...") | ||
238 | wg.Wait() | 281 | wg.Wait() |
239 | } | 282 | } |
240 | 283 | ||
@@ -333,6 +376,14 @@ func (c *Client) Exited() bool { | |||
333 | return c.exited | 376 | return c.exited |
334 | } | 377 | } |
335 | 378 | ||
379 | // killed is used in tests to check if a process failed to exit gracefully, and | ||
380 | // needed to be killed. | ||
381 | func (c *Client) killed() bool { | ||
382 | c.l.Lock() | ||
383 | defer c.l.Unlock() | ||
384 | return c.processKilled | ||
385 | } | ||
386 | |||
336 | // End the executing subprocess (if it is running) and perform any cleanup | 387 | // End the executing subprocess (if it is running) and perform any cleanup |
337 | // tasks necessary such as capturing any remaining logs and so on. | 388 | // tasks necessary such as capturing any remaining logs and so on. |
338 | // | 389 | // |
@@ -344,14 +395,24 @@ func (c *Client) Kill() { | |||
344 | c.l.Lock() | 395 | c.l.Lock() |
345 | process := c.process | 396 | process := c.process |
346 | addr := c.address | 397 | addr := c.address |
347 | doneCh := c.doneLogging | ||
348 | c.l.Unlock() | 398 | c.l.Unlock() |
349 | 399 | ||
350 | // If there is no process, we never started anything. Nothing to kill. | 400 | // If there is no process, there is nothing to kill. |
351 | if process == nil { | 401 | if process == nil { |
352 | return | 402 | return |
353 | } | 403 | } |
354 | 404 | ||
405 | defer func() { | ||
406 | // Wait for the all client goroutines to finish. | ||
407 | c.clientWaitGroup.Wait() | ||
408 | |||
409 | // Make sure there is no reference to the old process after it has been | ||
410 | // killed. | ||
411 | c.l.Lock() | ||
412 | c.process = nil | ||
413 | c.l.Unlock() | ||
414 | }() | ||
415 | |||
355 | // We need to check for address here. It is possible that the plugin | 416 | // We need to check for address here. It is possible that the plugin |
356 | // started (process != nil) but has no address (addr == nil) if the | 417 | // started (process != nil) but has no address (addr == nil) if the |
357 | // plugin failed at startup. If we do have an address, we need to close | 418 | // plugin failed at startup. If we do have an address, we need to close |
@@ -372,6 +433,8 @@ func (c *Client) Kill() { | |||
372 | // kill in a moment anyways. | 433 | // kill in a moment anyways. |
373 | c.logger.Warn("error closing client during Kill", "err", err) | 434 | c.logger.Warn("error closing client during Kill", "err", err) |
374 | } | 435 | } |
436 | } else { | ||
437 | c.logger.Error("client", "error", err) | ||
375 | } | 438 | } |
376 | } | 439 | } |
377 | 440 | ||
@@ -380,17 +443,20 @@ func (c *Client) Kill() { | |||
380 | // doneCh which would be closed if the process exits. | 443 | // doneCh which would be closed if the process exits. |
381 | if graceful { | 444 | if graceful { |
382 | select { | 445 | select { |
383 | case <-doneCh: | 446 | case <-c.doneCtx.Done(): |
447 | c.logger.Debug("plugin exited") | ||
384 | return | 448 | return |
385 | case <-time.After(250 * time.Millisecond): | 449 | case <-time.After(2 * time.Second): |
386 | } | 450 | } |
387 | } | 451 | } |
388 | 452 | ||
389 | // If graceful exiting failed, just kill it | 453 | // If graceful exiting failed, just kill it |
454 | c.logger.Warn("plugin failed to exit gracefully") | ||
390 | process.Kill() | 455 | process.Kill() |
391 | 456 | ||
392 | // Wait for the client to finish logging so we have a complete log | 457 | c.l.Lock() |
393 | <-doneCh | 458 | c.processKilled = true |
459 | c.l.Unlock() | ||
394 | } | 460 | } |
395 | 461 | ||
396 | // Starts the underlying subprocess, communicating with it to negotiate | 462 | // Starts the underlying subprocess, communicating with it to negotiate |
@@ -409,7 +475,7 @@ func (c *Client) Start() (addr net.Addr, err error) { | |||
409 | 475 | ||
410 | // If one of cmd or reattach isn't set, then it is an error. We wrap | 476 | // If one of cmd or reattach isn't set, then it is an error. We wrap |
411 | // this in a {} for scoping reasons, and hopeful that the escape | 477 | // this in a {} for scoping reasons, and hopeful that the escape |
412 | // analysis will pop the stock here. | 478 | // analysis will pop the stack here. |
413 | { | 479 | { |
414 | cmdSet := c.config.Cmd != nil | 480 | cmdSet := c.config.Cmd != nil |
415 | attachSet := c.config.Reattach != nil | 481 | attachSet := c.config.Reattach != nil |
@@ -423,77 +489,49 @@ func (c *Client) Start() (addr net.Addr, err error) { | |||
423 | } | 489 | } |
424 | } | 490 | } |
425 | 491 | ||
426 | // Create the logging channel for when we kill | ||
427 | c.doneLogging = make(chan struct{}) | ||
428 | // Create a context for when we kill | ||
429 | var ctxCancel context.CancelFunc | ||
430 | c.doneCtx, ctxCancel = context.WithCancel(context.Background()) | ||
431 | |||
432 | if c.config.Reattach != nil { | 492 | if c.config.Reattach != nil { |
433 | // Verify the process still exists. If not, then it is an error | 493 | return c.reattach() |
434 | p, err := os.FindProcess(c.config.Reattach.Pid) | 494 | } |
435 | if err != nil { | ||
436 | return nil, err | ||
437 | } | ||
438 | 495 | ||
439 | // Attempt to connect to the addr since on Unix systems FindProcess | 496 | if c.config.VersionedPlugins == nil { |
440 | // doesn't actually return an error if it can't find the process. | 497 | c.config.VersionedPlugins = make(map[int]PluginSet) |
441 | conn, err := net.Dial( | 498 | } |
442 | c.config.Reattach.Addr.Network(), | ||
443 | c.config.Reattach.Addr.String()) | ||
444 | if err != nil { | ||
445 | p.Kill() | ||
446 | return nil, ErrProcessNotFound | ||
447 | } | ||
448 | conn.Close() | ||
449 | |||
450 | // Goroutine to mark exit status | ||
451 | go func(pid int) { | ||
452 | // Wait for the process to die | ||
453 | pidWait(pid) | ||
454 | |||
455 | // Log so we can see it | ||
456 | c.logger.Debug("reattached plugin process exited") | ||
457 | |||
458 | // Mark it | ||
459 | c.l.Lock() | ||
460 | defer c.l.Unlock() | ||
461 | c.exited = true | ||
462 | |||
463 | // Close the logging channel since that doesn't work on reattach | ||
464 | close(c.doneLogging) | ||
465 | |||
466 | // Cancel the context | ||
467 | ctxCancel() | ||
468 | }(p.Pid) | ||
469 | |||
470 | // Set the address and process | ||
471 | c.address = c.config.Reattach.Addr | ||
472 | c.process = p | ||
473 | c.protocol = c.config.Reattach.Protocol | ||
474 | if c.protocol == "" { | ||
475 | // Default the protocol to net/rpc for backwards compatibility | ||
476 | c.protocol = ProtocolNetRPC | ||
477 | } | ||
478 | 499 | ||
479 | return c.address, nil | 500 | // handle all plugins as versioned, using the handshake config as the default. |
501 | version := int(c.config.ProtocolVersion) | ||
502 | |||
503 | // Make sure we're not overwriting a real version 0. If ProtocolVersion was | ||
504 | // non-zero, then we have to just assume the user made sure that | ||
505 | // VersionedPlugins doesn't conflict. | ||
506 | if _, ok := c.config.VersionedPlugins[version]; !ok && c.config.Plugins != nil { | ||
507 | c.config.VersionedPlugins[version] = c.config.Plugins | ||
508 | } | ||
509 | |||
510 | var versionStrings []string | ||
511 | for v := range c.config.VersionedPlugins { | ||
512 | versionStrings = append(versionStrings, strconv.Itoa(v)) | ||
480 | } | 513 | } |
481 | 514 | ||
482 | env := []string{ | 515 | env := []string{ |
483 | fmt.Sprintf("%s=%s", c.config.MagicCookieKey, c.config.MagicCookieValue), | 516 | fmt.Sprintf("%s=%s", c.config.MagicCookieKey, c.config.MagicCookieValue), |
484 | fmt.Sprintf("PLUGIN_MIN_PORT=%d", c.config.MinPort), | 517 | fmt.Sprintf("PLUGIN_MIN_PORT=%d", c.config.MinPort), |
485 | fmt.Sprintf("PLUGIN_MAX_PORT=%d", c.config.MaxPort), | 518 | fmt.Sprintf("PLUGIN_MAX_PORT=%d", c.config.MaxPort), |
519 | fmt.Sprintf("PLUGIN_PROTOCOL_VERSIONS=%s", strings.Join(versionStrings, ",")), | ||
486 | } | 520 | } |
487 | 521 | ||
488 | stdout_r, stdout_w := io.Pipe() | ||
489 | stderr_r, stderr_w := io.Pipe() | ||
490 | |||
491 | cmd := c.config.Cmd | 522 | cmd := c.config.Cmd |
492 | cmd.Env = append(cmd.Env, os.Environ()...) | 523 | cmd.Env = append(cmd.Env, os.Environ()...) |
493 | cmd.Env = append(cmd.Env, env...) | 524 | cmd.Env = append(cmd.Env, env...) |
494 | cmd.Stdin = os.Stdin | 525 | cmd.Stdin = os.Stdin |
495 | cmd.Stderr = stderr_w | 526 | |
496 | cmd.Stdout = stdout_w | 527 | cmdStdout, err := cmd.StdoutPipe() |
528 | if err != nil { | ||
529 | return nil, err | ||
530 | } | ||
531 | cmdStderr, err := cmd.StderrPipe() | ||
532 | if err != nil { | ||
533 | return nil, err | ||
534 | } | ||
497 | 535 | ||
498 | if c.config.SecureConfig != nil { | 536 | if c.config.SecureConfig != nil { |
499 | if ok, err := c.config.SecureConfig.Check(cmd.Path); err != nil { | 537 | if ok, err := c.config.SecureConfig.Check(cmd.Path); err != nil { |
@@ -503,6 +541,29 @@ func (c *Client) Start() (addr net.Addr, err error) { | |||
503 | } | 541 | } |
504 | } | 542 | } |
505 | 543 | ||
544 | // Setup a temporary certificate for client/server mtls, and send the public | ||
545 | // certificate to the plugin. | ||
546 | if c.config.AutoMTLS { | ||
547 | c.logger.Info("configuring client automatic mTLS") | ||
548 | certPEM, keyPEM, err := generateCert() | ||
549 | if err != nil { | ||
550 | c.logger.Error("failed to generate client certificate", "error", err) | ||
551 | return nil, err | ||
552 | } | ||
553 | cert, err := tls.X509KeyPair(certPEM, keyPEM) | ||
554 | if err != nil { | ||
555 | c.logger.Error("failed to parse client certificate", "error", err) | ||
556 | return nil, err | ||
557 | } | ||
558 | |||
559 | cmd.Env = append(cmd.Env, fmt.Sprintf("PLUGIN_CLIENT_CERT=%s", certPEM)) | ||
560 | |||
561 | c.config.TLSConfig = &tls.Config{ | ||
562 | Certificates: []tls.Certificate{cert}, | ||
563 | ServerName: "localhost", | ||
564 | } | ||
565 | } | ||
566 | |||
506 | c.logger.Debug("starting plugin", "path", cmd.Path, "args", cmd.Args) | 567 | c.logger.Debug("starting plugin", "path", cmd.Path, "args", cmd.Args) |
507 | err = cmd.Start() | 568 | err = cmd.Start() |
508 | if err != nil { | 569 | if err != nil { |
@@ -511,6 +572,7 @@ func (c *Client) Start() (addr net.Addr, err error) { | |||
511 | 572 | ||
512 | // Set the process | 573 | // Set the process |
513 | c.process = cmd.Process | 574 | c.process = cmd.Process |
575 | c.logger.Debug("plugin started", "path", cmd.Path, "pid", c.process.Pid) | ||
514 | 576 | ||
515 | // Make sure the command is properly cleaned up if there is an error | 577 | // Make sure the command is properly cleaned up if there is an error |
516 | defer func() { | 578 | defer func() { |
@@ -525,27 +587,37 @@ func (c *Client) Start() (addr net.Addr, err error) { | |||
525 | } | 587 | } |
526 | }() | 588 | }() |
527 | 589 | ||
528 | // Start goroutine to wait for process to exit | 590 | // Create a context for when we kill |
529 | exitCh := make(chan struct{}) | 591 | c.doneCtx, c.ctxCancel = context.WithCancel(context.Background()) |
592 | |||
593 | c.clientWaitGroup.Add(1) | ||
530 | go func() { | 594 | go func() { |
531 | // Make sure we close the write end of our stderr/stdout so | 595 | // ensure the context is cancelled when we're done |
532 | // that the readers send EOF properly. | 596 | defer c.ctxCancel() |
533 | defer stderr_w.Close() | 597 | |
534 | defer stdout_w.Close() | 598 | defer c.clientWaitGroup.Done() |
599 | |||
600 | // get the cmd info early, since the process information will be removed | ||
601 | // in Kill. | ||
602 | pid := c.process.Pid | ||
603 | path := cmd.Path | ||
535 | 604 | ||
536 | // Wait for the command to end. | 605 | // Wait for the command to end. |
537 | cmd.Wait() | 606 | err := cmd.Wait() |
607 | |||
608 | debugMsgArgs := []interface{}{ | ||
609 | "path", path, | ||
610 | "pid", pid, | ||
611 | } | ||
612 | if err != nil { | ||
613 | debugMsgArgs = append(debugMsgArgs, | ||
614 | []interface{}{"error", err.Error()}...) | ||
615 | } | ||
538 | 616 | ||
539 | // Log and make sure to flush the logs write away | 617 | // Log and make sure to flush the logs write away |
540 | c.logger.Debug("plugin process exited", "path", cmd.Path) | 618 | c.logger.Debug("plugin process exited", debugMsgArgs...) |
541 | os.Stderr.Sync() | 619 | os.Stderr.Sync() |
542 | 620 | ||
543 | // Mark that we exited | ||
544 | close(exitCh) | ||
545 | |||
546 | // Cancel the context, marking that we exited | ||
547 | ctxCancel() | ||
548 | |||
549 | // Set that we exited, which takes a lock | 621 | // Set that we exited, which takes a lock |
550 | c.l.Lock() | 622 | c.l.Lock() |
551 | defer c.l.Unlock() | 623 | defer c.l.Unlock() |
@@ -553,32 +625,33 @@ func (c *Client) Start() (addr net.Addr, err error) { | |||
553 | }() | 625 | }() |
554 | 626 | ||
555 | // Start goroutine that logs the stderr | 627 | // Start goroutine that logs the stderr |
556 | go c.logStderr(stderr_r) | 628 | c.clientWaitGroup.Add(1) |
629 | // logStderr calls Done() | ||
630 | go c.logStderr(cmdStderr) | ||
557 | 631 | ||
558 | // Start a goroutine that is going to be reading the lines | 632 | // Start a goroutine that is going to be reading the lines |
559 | // out of stdout | 633 | // out of stdout |
560 | linesCh := make(chan []byte) | 634 | linesCh := make(chan string) |
635 | c.clientWaitGroup.Add(1) | ||
561 | go func() { | 636 | go func() { |
637 | defer c.clientWaitGroup.Done() | ||
562 | defer close(linesCh) | 638 | defer close(linesCh) |
563 | 639 | ||
564 | buf := bufio.NewReader(stdout_r) | 640 | scanner := bufio.NewScanner(cmdStdout) |
565 | for { | 641 | for scanner.Scan() { |
566 | line, err := buf.ReadBytes('\n') | 642 | linesCh <- scanner.Text() |
567 | if line != nil { | ||
568 | linesCh <- line | ||
569 | } | ||
570 | |||
571 | if err == io.EOF { | ||
572 | return | ||
573 | } | ||
574 | } | 643 | } |
575 | }() | 644 | }() |
576 | 645 | ||
577 | // Make sure after we exit we read the lines from stdout forever | 646 | // Make sure after we exit we read the lines from stdout forever |
578 | // so they don't block since it is an io.Pipe | 647 | // so they don't block since it is a pipe. |
648 | // The scanner goroutine above will close this, but track it with a wait | ||
649 | // group for completeness. | ||
650 | c.clientWaitGroup.Add(1) | ||
579 | defer func() { | 651 | defer func() { |
580 | go func() { | 652 | go func() { |
581 | for _ = range linesCh { | 653 | defer c.clientWaitGroup.Done() |
654 | for range linesCh { | ||
582 | } | 655 | } |
583 | }() | 656 | }() |
584 | }() | 657 | }() |
@@ -591,12 +664,12 @@ func (c *Client) Start() (addr net.Addr, err error) { | |||
591 | select { | 664 | select { |
592 | case <-timeout: | 665 | case <-timeout: |
593 | err = errors.New("timeout while waiting for plugin to start") | 666 | err = errors.New("timeout while waiting for plugin to start") |
594 | case <-exitCh: | 667 | case <-c.doneCtx.Done(): |
595 | err = errors.New("plugin exited before we could connect") | 668 | err = errors.New("plugin exited before we could connect") |
596 | case lineBytes := <-linesCh: | 669 | case line := <-linesCh: |
597 | // Trim the line and split by "|" in order to get the parts of | 670 | // Trim the line and split by "|" in order to get the parts of |
598 | // the output. | 671 | // the output. |
599 | line := strings.TrimSpace(string(lineBytes)) | 672 | line = strings.TrimSpace(line) |
600 | parts := strings.SplitN(line, "|", 6) | 673 | parts := strings.SplitN(line, "|", 6) |
601 | if len(parts) < 4 { | 674 | if len(parts) < 4 { |
602 | err = fmt.Errorf( | 675 | err = fmt.Errorf( |
@@ -624,20 +697,18 @@ func (c *Client) Start() (addr net.Addr, err error) { | |||
624 | } | 697 | } |
625 | } | 698 | } |
626 | 699 | ||
627 | // Parse the protocol version | 700 | // Test the API version |
628 | var protocol int64 | 701 | version, pluginSet, err := c.checkProtoVersion(parts[1]) |
629 | protocol, err = strconv.ParseInt(parts[1], 10, 0) | ||
630 | if err != nil { | 702 | if err != nil { |
631 | err = fmt.Errorf("Error parsing protocol version: %s", err) | 703 | return addr, err |
632 | return | ||
633 | } | 704 | } |
634 | 705 | ||
635 | // Test the API version | 706 | // set the Plugins value to the compatible set, so the version |
636 | if uint(protocol) != c.config.ProtocolVersion { | 707 | // doesn't need to be passed through to the ClientProtocol |
637 | err = fmt.Errorf("Incompatible API version with plugin. "+ | 708 | // implementation. |
638 | "Plugin version: %s, Core version: %d", parts[1], c.config.ProtocolVersion) | 709 | c.config.Plugins = pluginSet |
639 | return | 710 | c.negotiatedVersion = version |
640 | } | 711 | c.logger.Debug("using plugin", "version", version) |
641 | 712 | ||
642 | switch parts[2] { | 713 | switch parts[2] { |
643 | case "tcp": | 714 | case "tcp": |
@@ -665,15 +736,125 @@ func (c *Client) Start() (addr net.Addr, err error) { | |||
665 | if !found { | 736 | if !found { |
666 | err = fmt.Errorf("Unsupported plugin protocol %q. Supported: %v", | 737 | err = fmt.Errorf("Unsupported plugin protocol %q. Supported: %v", |
667 | c.protocol, c.config.AllowedProtocols) | 738 | c.protocol, c.config.AllowedProtocols) |
668 | return | 739 | return addr, err |
669 | } | 740 | } |
670 | 741 | ||
742 | // See if we have a TLS certificate from the server. | ||
743 | // Checking if the length is > 50 rules out catching the unused "extra" | ||
744 | // data returned from some older implementations. | ||
745 | if len(parts) >= 6 && len(parts[5]) > 50 { | ||
746 | err := c.loadServerCert(parts[5]) | ||
747 | if err != nil { | ||
748 | return nil, fmt.Errorf("error parsing server cert: %s", err) | ||
749 | } | ||
750 | } | ||
671 | } | 751 | } |
672 | 752 | ||
673 | c.address = addr | 753 | c.address = addr |
674 | return | 754 | return |
675 | } | 755 | } |
676 | 756 | ||
757 | // loadServerCert is used by AutoMTLS to read an x.509 cert returned by the | ||
758 | // server, and load it as the RootCA for the client TLSConfig. | ||
759 | func (c *Client) loadServerCert(cert string) error { | ||
760 | certPool := x509.NewCertPool() | ||
761 | |||
762 | asn1, err := base64.RawStdEncoding.DecodeString(cert) | ||
763 | if err != nil { | ||
764 | return err | ||
765 | } | ||
766 | |||
767 | x509Cert, err := x509.ParseCertificate([]byte(asn1)) | ||
768 | if err != nil { | ||
769 | return err | ||
770 | } | ||
771 | |||
772 | certPool.AddCert(x509Cert) | ||
773 | |||
774 | c.config.TLSConfig.RootCAs = certPool | ||
775 | return nil | ||
776 | } | ||
777 | |||
778 | func (c *Client) reattach() (net.Addr, error) { | ||
779 | // Verify the process still exists. If not, then it is an error | ||
780 | p, err := os.FindProcess(c.config.Reattach.Pid) | ||
781 | if err != nil { | ||
782 | return nil, err | ||
783 | } | ||
784 | |||
785 | // Attempt to connect to the addr since on Unix systems FindProcess | ||
786 | // doesn't actually return an error if it can't find the process. | ||
787 | conn, err := net.Dial( | ||
788 | c.config.Reattach.Addr.Network(), | ||
789 | c.config.Reattach.Addr.String()) | ||
790 | if err != nil { | ||
791 | p.Kill() | ||
792 | return nil, ErrProcessNotFound | ||
793 | } | ||
794 | conn.Close() | ||
795 | |||
796 | // Create a context for when we kill | ||
797 | c.doneCtx, c.ctxCancel = context.WithCancel(context.Background()) | ||
798 | |||
799 | c.clientWaitGroup.Add(1) | ||
800 | // Goroutine to mark exit status | ||
801 | go func(pid int) { | ||
802 | defer c.clientWaitGroup.Done() | ||
803 | |||
804 | // ensure the context is cancelled when we're done | ||
805 | defer c.ctxCancel() | ||
806 | |||
807 | // Wait for the process to die | ||
808 | pidWait(pid) | ||
809 | |||
810 | // Log so we can see it | ||
811 | c.logger.Debug("reattached plugin process exited") | ||
812 | |||
813 | // Mark it | ||
814 | c.l.Lock() | ||
815 | defer c.l.Unlock() | ||
816 | c.exited = true | ||
817 | }(p.Pid) | ||
818 | |||
819 | // Set the address and process | ||
820 | c.address = c.config.Reattach.Addr | ||
821 | c.process = p | ||
822 | c.protocol = c.config.Reattach.Protocol | ||
823 | if c.protocol == "" { | ||
824 | // Default the protocol to net/rpc for backwards compatibility | ||
825 | c.protocol = ProtocolNetRPC | ||
826 | } | ||
827 | |||
828 | return c.address, nil | ||
829 | } | ||
830 | |||
831 | // checkProtoVersion returns the negotiated version and PluginSet. | ||
832 | // This returns an error if the server returned an incompatible protocol | ||
833 | // version, or an invalid handshake response. | ||
834 | func (c *Client) checkProtoVersion(protoVersion string) (int, PluginSet, error) { | ||
835 | serverVersion, err := strconv.Atoi(protoVersion) | ||
836 | if err != nil { | ||
837 | return 0, nil, fmt.Errorf("Error parsing protocol version %q: %s", protoVersion, err) | ||
838 | } | ||
839 | |||
840 | // record these for the error message | ||
841 | var clientVersions []int | ||
842 | |||
843 | // all versions, including the legacy ProtocolVersion have been added to | ||
844 | // the versions set | ||
845 | for version, plugins := range c.config.VersionedPlugins { | ||
846 | clientVersions = append(clientVersions, version) | ||
847 | |||
848 | if serverVersion != version { | ||
849 | continue | ||
850 | } | ||
851 | return version, plugins, nil | ||
852 | } | ||
853 | |||
854 | return 0, nil, fmt.Errorf("Incompatible API version with plugin. "+ | ||
855 | "Plugin version: %d, Client versions: %d", serverVersion, clientVersions) | ||
856 | } | ||
857 | |||
677 | // ReattachConfig returns the information that must be provided to NewClient | 858 | // ReattachConfig returns the information that must be provided to NewClient |
678 | // to reattach to the plugin process that this client started. This is | 859 | // to reattach to the plugin process that this client started. This is |
679 | // useful for plugins that detach from their parent process. | 860 | // useful for plugins that detach from their parent process. |
@@ -751,44 +932,84 @@ func (c *Client) dialer(_ string, timeout time.Duration) (net.Conn, error) { | |||
751 | return conn, nil | 932 | return conn, nil |
752 | } | 933 | } |
753 | 934 | ||
935 | var stdErrBufferSize = 64 * 1024 | ||
936 | |||
754 | func (c *Client) logStderr(r io.Reader) { | 937 | func (c *Client) logStderr(r io.Reader) { |
755 | bufR := bufio.NewReader(r) | 938 | defer c.clientWaitGroup.Done() |
939 | l := c.logger.Named(filepath.Base(c.config.Cmd.Path)) | ||
940 | |||
941 | reader := bufio.NewReaderSize(r, stdErrBufferSize) | ||
942 | // continuation indicates the previous line was a prefix | ||
943 | continuation := false | ||
944 | |||
756 | for { | 945 | for { |
757 | line, err := bufR.ReadString('\n') | 946 | line, isPrefix, err := reader.ReadLine() |
758 | if line != "" { | 947 | switch { |
759 | c.config.Stderr.Write([]byte(line)) | 948 | case err == io.EOF: |
760 | line = strings.TrimRightFunc(line, unicode.IsSpace) | 949 | return |
950 | case err != nil: | ||
951 | l.Error("reading plugin stderr", "error", err) | ||
952 | return | ||
953 | } | ||
761 | 954 | ||
762 | l := c.logger.Named(filepath.Base(c.config.Cmd.Path)) | 955 | c.config.Stderr.Write(line) |
763 | 956 | ||
764 | entry, err := parseJSON(line) | 957 | // The line was longer than our max token size, so it's likely |
765 | // If output is not JSON format, print directly to Debug | 958 | // incomplete and won't unmarshal. |
766 | if err != nil { | 959 | if isPrefix || continuation { |
767 | l.Debug(line) | 960 | l.Debug(string(line)) |
768 | } else { | 961 | |
769 | out := flattenKVPairs(entry.KVPairs) | 962 | // if we're finishing a continued line, add the newline back in |
770 | 963 | if !isPrefix { | |
771 | l = l.With("timestamp", entry.Timestamp.Format(hclog.TimeFormat)) | 964 | c.config.Stderr.Write([]byte{'\n'}) |
772 | switch hclog.LevelFromString(entry.Level) { | ||
773 | case hclog.Trace: | ||
774 | l.Trace(entry.Message, out...) | ||
775 | case hclog.Debug: | ||
776 | l.Debug(entry.Message, out...) | ||
777 | case hclog.Info: | ||
778 | l.Info(entry.Message, out...) | ||
779 | case hclog.Warn: | ||
780 | l.Warn(entry.Message, out...) | ||
781 | case hclog.Error: | ||
782 | l.Error(entry.Message, out...) | ||
783 | } | ||
784 | } | 965 | } |
966 | |||
967 | continuation = isPrefix | ||
968 | continue | ||
785 | } | 969 | } |
786 | 970 | ||
787 | if err == io.EOF { | 971 | c.config.Stderr.Write([]byte{'\n'}) |
788 | break | 972 | |
973 | entry, err := parseJSON(line) | ||
974 | // If output is not JSON format, print directly to Debug | ||
975 | if err != nil { | ||
976 | // Attempt to infer the desired log level from the commonly used | ||
977 | // string prefixes | ||
978 | switch line := string(line); { | ||
979 | case strings.HasPrefix(line, "[TRACE]"): | ||
980 | l.Trace(line) | ||
981 | case strings.HasPrefix(line, "[DEBUG]"): | ||
982 | l.Debug(line) | ||
983 | case strings.HasPrefix(line, "[INFO]"): | ||
984 | l.Info(line) | ||
985 | case strings.HasPrefix(line, "[WARN]"): | ||
986 | l.Warn(line) | ||
987 | case strings.HasPrefix(line, "[ERROR]"): | ||
988 | l.Error(line) | ||
989 | default: | ||
990 | l.Debug(line) | ||
991 | } | ||
992 | } else { | ||
993 | out := flattenKVPairs(entry.KVPairs) | ||
994 | |||
995 | out = append(out, "timestamp", entry.Timestamp.Format(hclog.TimeFormat)) | ||
996 | switch hclog.LevelFromString(entry.Level) { | ||
997 | case hclog.Trace: | ||
998 | l.Trace(entry.Message, out...) | ||
999 | case hclog.Debug: | ||
1000 | l.Debug(entry.Message, out...) | ||
1001 | case hclog.Info: | ||
1002 | l.Info(entry.Message, out...) | ||
1003 | case hclog.Warn: | ||
1004 | l.Warn(entry.Message, out...) | ||
1005 | case hclog.Error: | ||
1006 | l.Error(entry.Message, out...) | ||
1007 | default: | ||
1008 | // if there was no log level, it's likely this is unexpected | ||
1009 | // json from something other than hclog, and we should output | ||
1010 | // it verbatim. | ||
1011 | l.Debug(string(line)) | ||
1012 | } | ||
789 | } | 1013 | } |
790 | } | 1014 | } |
791 | |||
792 | // Flag that we've completed logging for others | ||
793 | close(c.doneLogging) | ||
794 | } | 1015 | } |
diff --git a/vendor/github.com/hashicorp/go-plugin/go.mod b/vendor/github.com/hashicorp/go-plugin/go.mod new file mode 100644 index 0000000..f3ddf44 --- /dev/null +++ b/vendor/github.com/hashicorp/go-plugin/go.mod | |||
@@ -0,0 +1,17 @@ | |||
1 | module github.com/hashicorp/go-plugin | ||
2 | |||
3 | require ( | ||
4 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b // indirect | ||
5 | github.com/golang/protobuf v1.2.0 | ||
6 | github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd | ||
7 | github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb | ||
8 | github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77 | ||
9 | github.com/oklog/run v1.0.0 | ||
10 | github.com/stretchr/testify v1.3.0 // indirect | ||
11 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d | ||
12 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 // indirect | ||
13 | golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc // indirect | ||
14 | golang.org/x/text v0.3.0 // indirect | ||
15 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 // indirect | ||
16 | google.golang.org/grpc v1.14.0 | ||
17 | ) | ||
diff --git a/vendor/github.com/hashicorp/go-plugin/go.sum b/vendor/github.com/hashicorp/go-plugin/go.sum new file mode 100644 index 0000000..21b14e9 --- /dev/null +++ b/vendor/github.com/hashicorp/go-plugin/go.sum | |||
@@ -0,0 +1,31 @@ | |||
1 | github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= | ||
2 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
3 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= | ||
4 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= | ||
5 | github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= | ||
6 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= | ||
7 | github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd h1:rNuUHR+CvK1IS89MMtcF0EpcVMZtjKfPRp4MEmt/aTs= | ||
8 | github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI= | ||
9 | github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M= | ||
10 | github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= | ||
11 | github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77 h1:7GoSOOW2jpsfkntVKaS2rAr1TJqfcxotyaUcuxoZSzg= | ||
12 | github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= | ||
13 | github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= | ||
14 | github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= | ||
15 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||
16 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||
17 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||
18 | github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= | ||
19 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= | ||
20 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d h1:g9qWBGx4puODJTMVyoPrpoxPFgVGd+z1DZwjfRu4d0I= | ||
21 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | ||
22 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= | ||
23 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||
24 | golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc h1:WiYx1rIFmx8c0mXAFtv5D/mHyKe1+jmuP7PViuwqwuQ= | ||
25 | golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||
26 | golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= | ||
27 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | ||
28 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc= | ||
29 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= | ||
30 | google.golang.org/grpc v1.14.0 h1:ArxJuB1NWfPY6r9Gp9gqwplT0Ge7nqv9msgu03lHLmo= | ||
31 | google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= | ||
diff --git a/vendor/github.com/hashicorp/go-plugin/grpc_broker.go b/vendor/github.com/hashicorp/go-plugin/grpc_broker.go index 49fd21c..daf142d 100644 --- a/vendor/github.com/hashicorp/go-plugin/grpc_broker.go +++ b/vendor/github.com/hashicorp/go-plugin/grpc_broker.go | |||
@@ -11,6 +11,8 @@ import ( | |||
11 | "sync/atomic" | 11 | "sync/atomic" |
12 | "time" | 12 | "time" |
13 | 13 | ||
14 | "github.com/hashicorp/go-plugin/internal/plugin" | ||
15 | |||
14 | "github.com/oklog/run" | 16 | "github.com/oklog/run" |
15 | "google.golang.org/grpc" | 17 | "google.golang.org/grpc" |
16 | "google.golang.org/grpc/credentials" | 18 | "google.golang.org/grpc/credentials" |
@@ -19,14 +21,14 @@ import ( | |||
19 | // streamer interface is used in the broker to send/receive connection | 21 | // streamer interface is used in the broker to send/receive connection |
20 | // information. | 22 | // information. |
21 | type streamer interface { | 23 | type streamer interface { |
22 | Send(*ConnInfo) error | 24 | Send(*plugin.ConnInfo) error |
23 | Recv() (*ConnInfo, error) | 25 | Recv() (*plugin.ConnInfo, error) |
24 | Close() | 26 | Close() |
25 | } | 27 | } |
26 | 28 | ||
27 | // sendErr is used to pass errors back during a send. | 29 | // sendErr is used to pass errors back during a send. |
28 | type sendErr struct { | 30 | type sendErr struct { |
29 | i *ConnInfo | 31 | i *plugin.ConnInfo |
30 | ch chan error | 32 | ch chan error |
31 | } | 33 | } |
32 | 34 | ||
@@ -38,7 +40,7 @@ type gRPCBrokerServer struct { | |||
38 | send chan *sendErr | 40 | send chan *sendErr |
39 | 41 | ||
40 | // recv is used to receive connection info from the gRPC stream. | 42 | // recv is used to receive connection info from the gRPC stream. |
41 | recv chan *ConnInfo | 43 | recv chan *plugin.ConnInfo |
42 | 44 | ||
43 | // quit closes down the stream. | 45 | // quit closes down the stream. |
44 | quit chan struct{} | 46 | quit chan struct{} |
@@ -50,7 +52,7 @@ type gRPCBrokerServer struct { | |||
50 | func newGRPCBrokerServer() *gRPCBrokerServer { | 52 | func newGRPCBrokerServer() *gRPCBrokerServer { |
51 | return &gRPCBrokerServer{ | 53 | return &gRPCBrokerServer{ |
52 | send: make(chan *sendErr), | 54 | send: make(chan *sendErr), |
53 | recv: make(chan *ConnInfo), | 55 | recv: make(chan *plugin.ConnInfo), |
54 | quit: make(chan struct{}), | 56 | quit: make(chan struct{}), |
55 | } | 57 | } |
56 | } | 58 | } |
@@ -58,7 +60,7 @@ func newGRPCBrokerServer() *gRPCBrokerServer { | |||
58 | // StartStream implements the GRPCBrokerServer interface and will block until | 60 | // StartStream implements the GRPCBrokerServer interface and will block until |
59 | // the quit channel is closed or the context reports Done. The stream will pass | 61 | // the quit channel is closed or the context reports Done. The stream will pass |
60 | // connection information to/from the client. | 62 | // connection information to/from the client. |
61 | func (s *gRPCBrokerServer) StartStream(stream GRPCBroker_StartStreamServer) error { | 63 | func (s *gRPCBrokerServer) StartStream(stream plugin.GRPCBroker_StartStreamServer) error { |
62 | doneCh := stream.Context().Done() | 64 | doneCh := stream.Context().Done() |
63 | defer s.Close() | 65 | defer s.Close() |
64 | 66 | ||
@@ -97,7 +99,7 @@ func (s *gRPCBrokerServer) StartStream(stream GRPCBroker_StartStreamServer) erro | |||
97 | 99 | ||
98 | // Send is used by the GRPCBroker to pass connection information into the stream | 100 | // Send is used by the GRPCBroker to pass connection information into the stream |
99 | // to the client. | 101 | // to the client. |
100 | func (s *gRPCBrokerServer) Send(i *ConnInfo) error { | 102 | func (s *gRPCBrokerServer) Send(i *plugin.ConnInfo) error { |
101 | ch := make(chan error) | 103 | ch := make(chan error) |
102 | defer close(ch) | 104 | defer close(ch) |
103 | 105 | ||
@@ -115,7 +117,7 @@ func (s *gRPCBrokerServer) Send(i *ConnInfo) error { | |||
115 | 117 | ||
116 | // Recv is used by the GRPCBroker to pass connection information that has been | 118 | // Recv is used by the GRPCBroker to pass connection information that has been |
117 | // sent from the client from the stream to the broker. | 119 | // sent from the client from the stream to the broker. |
118 | func (s *gRPCBrokerServer) Recv() (*ConnInfo, error) { | 120 | func (s *gRPCBrokerServer) Recv() (*plugin.ConnInfo, error) { |
119 | select { | 121 | select { |
120 | case <-s.quit: | 122 | case <-s.quit: |
121 | return nil, errors.New("broker closed") | 123 | return nil, errors.New("broker closed") |
@@ -136,13 +138,13 @@ func (s *gRPCBrokerServer) Close() { | |||
136 | // streamer interfaces. | 138 | // streamer interfaces. |
137 | type gRPCBrokerClientImpl struct { | 139 | type gRPCBrokerClientImpl struct { |
138 | // client is the underlying GRPC client used to make calls to the server. | 140 | // client is the underlying GRPC client used to make calls to the server. |
139 | client GRPCBrokerClient | 141 | client plugin.GRPCBrokerClient |
140 | 142 | ||
141 | // send is used to send connection info to the gRPC stream. | 143 | // send is used to send connection info to the gRPC stream. |
142 | send chan *sendErr | 144 | send chan *sendErr |
143 | 145 | ||
144 | // recv is used to receive connection info from the gRPC stream. | 146 | // recv is used to receive connection info from the gRPC stream. |
145 | recv chan *ConnInfo | 147 | recv chan *plugin.ConnInfo |
146 | 148 | ||
147 | // quit closes down the stream. | 149 | // quit closes down the stream. |
148 | quit chan struct{} | 150 | quit chan struct{} |
@@ -153,9 +155,9 @@ type gRPCBrokerClientImpl struct { | |||
153 | 155 | ||
154 | func newGRPCBrokerClient(conn *grpc.ClientConn) *gRPCBrokerClientImpl { | 156 | func newGRPCBrokerClient(conn *grpc.ClientConn) *gRPCBrokerClientImpl { |
155 | return &gRPCBrokerClientImpl{ | 157 | return &gRPCBrokerClientImpl{ |
156 | client: NewGRPCBrokerClient(conn), | 158 | client: plugin.NewGRPCBrokerClient(conn), |
157 | send: make(chan *sendErr), | 159 | send: make(chan *sendErr), |
158 | recv: make(chan *ConnInfo), | 160 | recv: make(chan *plugin.ConnInfo), |
159 | quit: make(chan struct{}), | 161 | quit: make(chan struct{}), |
160 | } | 162 | } |
161 | } | 163 | } |
@@ -207,7 +209,7 @@ func (s *gRPCBrokerClientImpl) StartStream() error { | |||
207 | 209 | ||
208 | // Send is used by the GRPCBroker to pass connection information into the stream | 210 | // Send is used by the GRPCBroker to pass connection information into the stream |
209 | // to the plugin. | 211 | // to the plugin. |
210 | func (s *gRPCBrokerClientImpl) Send(i *ConnInfo) error { | 212 | func (s *gRPCBrokerClientImpl) Send(i *plugin.ConnInfo) error { |
211 | ch := make(chan error) | 213 | ch := make(chan error) |
212 | defer close(ch) | 214 | defer close(ch) |
213 | 215 | ||
@@ -225,7 +227,7 @@ func (s *gRPCBrokerClientImpl) Send(i *ConnInfo) error { | |||
225 | 227 | ||
226 | // Recv is used by the GRPCBroker to pass connection information that has been | 228 | // Recv is used by the GRPCBroker to pass connection information that has been |
227 | // sent from the plugin to the broker. | 229 | // sent from the plugin to the broker. |
228 | func (s *gRPCBrokerClientImpl) Recv() (*ConnInfo, error) { | 230 | func (s *gRPCBrokerClientImpl) Recv() (*plugin.ConnInfo, error) { |
229 | select { | 231 | select { |
230 | case <-s.quit: | 232 | case <-s.quit: |
231 | return nil, errors.New("broker closed") | 233 | return nil, errors.New("broker closed") |
@@ -266,7 +268,7 @@ type GRPCBroker struct { | |||
266 | } | 268 | } |
267 | 269 | ||
268 | type gRPCBrokerPending struct { | 270 | type gRPCBrokerPending struct { |
269 | ch chan *ConnInfo | 271 | ch chan *plugin.ConnInfo |
270 | doneCh chan struct{} | 272 | doneCh chan struct{} |
271 | } | 273 | } |
272 | 274 | ||
@@ -288,7 +290,7 @@ func (b *GRPCBroker) Accept(id uint32) (net.Listener, error) { | |||
288 | return nil, err | 290 | return nil, err |
289 | } | 291 | } |
290 | 292 | ||
291 | err = b.streamer.Send(&ConnInfo{ | 293 | err = b.streamer.Send(&plugin.ConnInfo{ |
292 | ServiceId: id, | 294 | ServiceId: id, |
293 | Network: listener.Addr().Network(), | 295 | Network: listener.Addr().Network(), |
294 | Address: listener.Addr().String(), | 296 | Address: listener.Addr().String(), |
@@ -363,7 +365,7 @@ func (b *GRPCBroker) Close() error { | |||
363 | 365 | ||
364 | // Dial opens a connection by ID. | 366 | // Dial opens a connection by ID. |
365 | func (b *GRPCBroker) Dial(id uint32) (conn *grpc.ClientConn, err error) { | 367 | func (b *GRPCBroker) Dial(id uint32) (conn *grpc.ClientConn, err error) { |
366 | var c *ConnInfo | 368 | var c *plugin.ConnInfo |
367 | 369 | ||
368 | // Open the stream | 370 | // Open the stream |
369 | p := b.getStream(id) | 371 | p := b.getStream(id) |
@@ -433,7 +435,7 @@ func (m *GRPCBroker) getStream(id uint32) *gRPCBrokerPending { | |||
433 | } | 435 | } |
434 | 436 | ||
435 | m.streams[id] = &gRPCBrokerPending{ | 437 | m.streams[id] = &gRPCBrokerPending{ |
436 | ch: make(chan *ConnInfo, 1), | 438 | ch: make(chan *plugin.ConnInfo, 1), |
437 | doneCh: make(chan struct{}), | 439 | doneCh: make(chan struct{}), |
438 | } | 440 | } |
439 | return m.streams[id] | 441 | return m.streams[id] |
diff --git a/vendor/github.com/hashicorp/go-plugin/grpc_client.go b/vendor/github.com/hashicorp/go-plugin/grpc_client.go index 44294d0..294518e 100644 --- a/vendor/github.com/hashicorp/go-plugin/grpc_client.go +++ b/vendor/github.com/hashicorp/go-plugin/grpc_client.go | |||
@@ -6,6 +6,7 @@ import ( | |||
6 | "net" | 6 | "net" |
7 | "time" | 7 | "time" |
8 | 8 | ||
9 | "github.com/hashicorp/go-plugin/internal/plugin" | ||
9 | "golang.org/x/net/context" | 10 | "golang.org/x/net/context" |
10 | "google.golang.org/grpc" | 11 | "google.golang.org/grpc" |
11 | "google.golang.org/grpc/credentials" | 12 | "google.golang.org/grpc/credentials" |
@@ -16,12 +17,9 @@ func dialGRPCConn(tls *tls.Config, dialer func(string, time.Duration) (net.Conn, | |||
16 | // Build dialing options. | 17 | // Build dialing options. |
17 | opts := make([]grpc.DialOption, 0, 5) | 18 | opts := make([]grpc.DialOption, 0, 5) |
18 | 19 | ||
19 | // We use a custom dialer so that we can connect over unix domain sockets | 20 | // We use a custom dialer so that we can connect over unix domain sockets. |
20 | opts = append(opts, grpc.WithDialer(dialer)) | 21 | opts = append(opts, grpc.WithDialer(dialer)) |
21 | 22 | ||
22 | // go-plugin expects to block the connection | ||
23 | opts = append(opts, grpc.WithBlock()) | ||
24 | |||
25 | // Fail right away | 23 | // Fail right away |
26 | opts = append(opts, grpc.FailOnNonTempDialError(true)) | 24 | opts = append(opts, grpc.FailOnNonTempDialError(true)) |
27 | 25 | ||
@@ -58,12 +56,15 @@ func newGRPCClient(doneCtx context.Context, c *Client) (*GRPCClient, error) { | |||
58 | go broker.Run() | 56 | go broker.Run() |
59 | go brokerGRPCClient.StartStream() | 57 | go brokerGRPCClient.StartStream() |
60 | 58 | ||
61 | return &GRPCClient{ | 59 | cl := &GRPCClient{ |
62 | Conn: conn, | 60 | Conn: conn, |
63 | Plugins: c.config.Plugins, | 61 | Plugins: c.config.Plugins, |
64 | doneCtx: doneCtx, | 62 | doneCtx: doneCtx, |
65 | broker: broker, | 63 | broker: broker, |
66 | }, nil | 64 | controller: plugin.NewGRPCControllerClient(conn), |
65 | } | ||
66 | |||
67 | return cl, nil | ||
67 | } | 68 | } |
68 | 69 | ||
69 | // GRPCClient connects to a GRPCServer over gRPC to dispense plugin types. | 70 | // GRPCClient connects to a GRPCServer over gRPC to dispense plugin types. |
@@ -73,11 +74,14 @@ type GRPCClient struct { | |||
73 | 74 | ||
74 | doneCtx context.Context | 75 | doneCtx context.Context |
75 | broker *GRPCBroker | 76 | broker *GRPCBroker |
77 | |||
78 | controller plugin.GRPCControllerClient | ||
76 | } | 79 | } |
77 | 80 | ||
78 | // ClientProtocol impl. | 81 | // ClientProtocol impl. |
79 | func (c *GRPCClient) Close() error { | 82 | func (c *GRPCClient) Close() error { |
80 | c.broker.Close() | 83 | c.broker.Close() |
84 | c.controller.Shutdown(c.doneCtx, &plugin.Empty{}) | ||
81 | return c.Conn.Close() | 85 | return c.Conn.Close() |
82 | } | 86 | } |
83 | 87 | ||
diff --git a/vendor/github.com/hashicorp/go-plugin/grpc_controller.go b/vendor/github.com/hashicorp/go-plugin/grpc_controller.go new file mode 100644 index 0000000..1a8a8e7 --- /dev/null +++ b/vendor/github.com/hashicorp/go-plugin/grpc_controller.go | |||
@@ -0,0 +1,23 @@ | |||
1 | package plugin | ||
2 | |||
3 | import ( | ||
4 | "context" | ||
5 | |||
6 | "github.com/hashicorp/go-plugin/internal/plugin" | ||
7 | ) | ||
8 | |||
9 | // GRPCControllerServer handles shutdown calls to terminate the server when the | ||
10 | // plugin client is closed. | ||
11 | type grpcControllerServer struct { | ||
12 | server *GRPCServer | ||
13 | } | ||
14 | |||
15 | // Shutdown stops the grpc server. It first will attempt a graceful stop, then a | ||
16 | // full stop on the server. | ||
17 | func (s *grpcControllerServer) Shutdown(ctx context.Context, _ *plugin.Empty) (*plugin.Empty, error) { | ||
18 | resp := &plugin.Empty{} | ||
19 | |||
20 | // TODO: figure out why GracefullStop doesn't work. | ||
21 | s.server.Stop() | ||
22 | return resp, nil | ||
23 | } | ||
diff --git a/vendor/github.com/hashicorp/go-plugin/grpc_server.go b/vendor/github.com/hashicorp/go-plugin/grpc_server.go index 3a72739..d3dbf1c 100644 --- a/vendor/github.com/hashicorp/go-plugin/grpc_server.go +++ b/vendor/github.com/hashicorp/go-plugin/grpc_server.go | |||
@@ -8,6 +8,8 @@ import ( | |||
8 | "io" | 8 | "io" |
9 | "net" | 9 | "net" |
10 | 10 | ||
11 | hclog "github.com/hashicorp/go-hclog" | ||
12 | "github.com/hashicorp/go-plugin/internal/plugin" | ||
11 | "google.golang.org/grpc" | 13 | "google.golang.org/grpc" |
12 | "google.golang.org/grpc/credentials" | 14 | "google.golang.org/grpc/credentials" |
13 | "google.golang.org/grpc/health" | 15 | "google.golang.org/grpc/health" |
@@ -52,6 +54,8 @@ type GRPCServer struct { | |||
52 | config GRPCServerConfig | 54 | config GRPCServerConfig |
53 | server *grpc.Server | 55 | server *grpc.Server |
54 | broker *GRPCBroker | 56 | broker *GRPCBroker |
57 | |||
58 | logger hclog.Logger | ||
55 | } | 59 | } |
56 | 60 | ||
57 | // ServerProtocol impl. | 61 | // ServerProtocol impl. |
@@ -71,10 +75,16 @@ func (s *GRPCServer) Init() error { | |||
71 | 75 | ||
72 | // Register the broker service | 76 | // Register the broker service |
73 | brokerServer := newGRPCBrokerServer() | 77 | brokerServer := newGRPCBrokerServer() |
74 | RegisterGRPCBrokerServer(s.server, brokerServer) | 78 | plugin.RegisterGRPCBrokerServer(s.server, brokerServer) |
75 | s.broker = newGRPCBroker(brokerServer, s.TLS) | 79 | s.broker = newGRPCBroker(brokerServer, s.TLS) |
76 | go s.broker.Run() | 80 | go s.broker.Run() |
77 | 81 | ||
82 | // Register the controller | ||
83 | controllerServer := &grpcControllerServer{ | ||
84 | server: s, | ||
85 | } | ||
86 | plugin.RegisterGRPCControllerServer(s.server, controllerServer) | ||
87 | |||
78 | // Register all our plugins onto the gRPC server. | 88 | // Register all our plugins onto the gRPC server. |
79 | for k, raw := range s.Plugins { | 89 | for k, raw := range s.Plugins { |
80 | p, ok := raw.(GRPCPlugin) | 90 | p, ok := raw.(GRPCPlugin) |
@@ -83,7 +93,7 @@ func (s *GRPCServer) Init() error { | |||
83 | } | 93 | } |
84 | 94 | ||
85 | if err := p.GRPCServer(s.broker, s.server); err != nil { | 95 | if err := p.GRPCServer(s.broker, s.server); err != nil { |
86 | return fmt.Errorf("error registring %q: %s", k, err) | 96 | return fmt.Errorf("error registering %q: %s", k, err) |
87 | } | 97 | } |
88 | } | 98 | } |
89 | 99 | ||
@@ -117,11 +127,11 @@ func (s *GRPCServer) Config() string { | |||
117 | } | 127 | } |
118 | 128 | ||
119 | func (s *GRPCServer) Serve(lis net.Listener) { | 129 | func (s *GRPCServer) Serve(lis net.Listener) { |
120 | // Start serving in a goroutine | 130 | defer close(s.DoneCh) |
121 | go s.server.Serve(lis) | 131 | err := s.server.Serve(lis) |
122 | 132 | if err != nil { | |
123 | // Wait until graceful completion | 133 | s.logger.Error("grpc server", "error", err) |
124 | <-s.DoneCh | 134 | } |
125 | } | 135 | } |
126 | 136 | ||
127 | // GRPCServerConfig is the extra configuration passed along for consumers | 137 | // GRPCServerConfig is the extra configuration passed along for consumers |
diff --git a/vendor/github.com/hashicorp/go-plugin/internal/plugin/gen.go b/vendor/github.com/hashicorp/go-plugin/internal/plugin/gen.go new file mode 100644 index 0000000..aa2fdc8 --- /dev/null +++ b/vendor/github.com/hashicorp/go-plugin/internal/plugin/gen.go | |||
@@ -0,0 +1,3 @@ | |||
1 | //go:generate protoc -I ./ ./grpc_broker.proto ./grpc_controller.proto --go_out=plugins=grpc:. | ||
2 | |||
3 | package plugin | ||
diff --git a/vendor/github.com/hashicorp/go-plugin/grpc_broker.pb.go b/vendor/github.com/hashicorp/go-plugin/internal/plugin/grpc_broker.pb.go index d490daf..b6850aa 100644 --- a/vendor/github.com/hashicorp/go-plugin/grpc_broker.pb.go +++ b/vendor/github.com/hashicorp/go-plugin/internal/plugin/grpc_broker.pb.go | |||
@@ -1,24 +1,14 @@ | |||
1 | // Code generated by protoc-gen-go. DO NOT EDIT. | 1 | // Code generated by protoc-gen-go. DO NOT EDIT. |
2 | // source: grpc_broker.proto | 2 | // source: grpc_broker.proto |
3 | 3 | ||
4 | /* | ||
5 | Package plugin is a generated protocol buffer package. | ||
6 | |||
7 | It is generated from these files: | ||
8 | grpc_broker.proto | ||
9 | |||
10 | It has these top-level messages: | ||
11 | ConnInfo | ||
12 | */ | ||
13 | package plugin | 4 | package plugin |
14 | 5 | ||
15 | import proto "github.com/golang/protobuf/proto" | ||
16 | import fmt "fmt" | ||
17 | import math "math" | ||
18 | |||
19 | import ( | 6 | import ( |
7 | fmt "fmt" | ||
8 | proto "github.com/golang/protobuf/proto" | ||
20 | context "golang.org/x/net/context" | 9 | context "golang.org/x/net/context" |
21 | grpc "google.golang.org/grpc" | 10 | grpc "google.golang.org/grpc" |
11 | math "math" | ||
22 | ) | 12 | ) |
23 | 13 | ||
24 | // Reference imports to suppress errors if they are not otherwise used. | 14 | // Reference imports to suppress errors if they are not otherwise used. |
@@ -33,15 +23,38 @@ var _ = math.Inf | |||
33 | const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package | 23 | const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package |
34 | 24 | ||
35 | type ConnInfo struct { | 25 | type ConnInfo struct { |
36 | ServiceId uint32 `protobuf:"varint,1,opt,name=service_id,json=serviceId" json:"service_id,omitempty"` | 26 | ServiceId uint32 `protobuf:"varint,1,opt,name=service_id,json=serviceId,proto3" json:"service_id,omitempty"` |
37 | Network string `protobuf:"bytes,2,opt,name=network" json:"network,omitempty"` | 27 | Network string `protobuf:"bytes,2,opt,name=network,proto3" json:"network,omitempty"` |
38 | Address string `protobuf:"bytes,3,opt,name=address" json:"address,omitempty"` | 28 | Address string `protobuf:"bytes,3,opt,name=address,proto3" json:"address,omitempty"` |
29 | XXX_NoUnkeyedLiteral struct{} `json:"-"` | ||
30 | XXX_unrecognized []byte `json:"-"` | ||
31 | XXX_sizecache int32 `json:"-"` | ||
32 | } | ||
33 | |||
34 | func (m *ConnInfo) Reset() { *m = ConnInfo{} } | ||
35 | func (m *ConnInfo) String() string { return proto.CompactTextString(m) } | ||
36 | func (*ConnInfo) ProtoMessage() {} | ||
37 | func (*ConnInfo) Descriptor() ([]byte, []int) { | ||
38 | return fileDescriptor_802e9beed3ec3b28, []int{0} | ||
39 | } | 39 | } |
40 | 40 | ||
41 | func (m *ConnInfo) Reset() { *m = ConnInfo{} } | 41 | func (m *ConnInfo) XXX_Unmarshal(b []byte) error { |
42 | func (m *ConnInfo) String() string { return proto.CompactTextString(m) } | 42 | return xxx_messageInfo_ConnInfo.Unmarshal(m, b) |
43 | func (*ConnInfo) ProtoMessage() {} | 43 | } |
44 | func (*ConnInfo) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } | 44 | func (m *ConnInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { |
45 | return xxx_messageInfo_ConnInfo.Marshal(b, m, deterministic) | ||
46 | } | ||
47 | func (m *ConnInfo) XXX_Merge(src proto.Message) { | ||
48 | xxx_messageInfo_ConnInfo.Merge(m, src) | ||
49 | } | ||
50 | func (m *ConnInfo) XXX_Size() int { | ||
51 | return xxx_messageInfo_ConnInfo.Size(m) | ||
52 | } | ||
53 | func (m *ConnInfo) XXX_DiscardUnknown() { | ||
54 | xxx_messageInfo_ConnInfo.DiscardUnknown(m) | ||
55 | } | ||
56 | |||
57 | var xxx_messageInfo_ConnInfo proto.InternalMessageInfo | ||
45 | 58 | ||
46 | func (m *ConnInfo) GetServiceId() uint32 { | 59 | func (m *ConnInfo) GetServiceId() uint32 { |
47 | if m != nil { | 60 | if m != nil { |
@@ -68,6 +81,23 @@ func init() { | |||
68 | proto.RegisterType((*ConnInfo)(nil), "plugin.ConnInfo") | 81 | proto.RegisterType((*ConnInfo)(nil), "plugin.ConnInfo") |
69 | } | 82 | } |
70 | 83 | ||
84 | func init() { proto.RegisterFile("grpc_broker.proto", fileDescriptor_802e9beed3ec3b28) } | ||
85 | |||
86 | var fileDescriptor_802e9beed3ec3b28 = []byte{ | ||
87 | // 175 bytes of a gzipped FileDescriptorProto | ||
88 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x4c, 0x2f, 0x2a, 0x48, | ||
89 | 0x8e, 0x4f, 0x2a, 0xca, 0xcf, 0x4e, 0x2d, 0xd2, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x2b, | ||
90 | 0xc8, 0x29, 0x4d, 0xcf, 0xcc, 0x53, 0x8a, 0xe5, 0xe2, 0x70, 0xce, 0xcf, 0xcb, 0xf3, 0xcc, 0x4b, | ||
91 | 0xcb, 0x17, 0x92, 0xe5, 0xe2, 0x2a, 0x4e, 0x2d, 0x2a, 0xcb, 0x4c, 0x4e, 0x8d, 0xcf, 0x4c, 0x91, | ||
92 | 0x60, 0x54, 0x60, 0xd4, 0xe0, 0x0d, 0xe2, 0x84, 0x8a, 0x78, 0xa6, 0x08, 0x49, 0x70, 0xb1, 0xe7, | ||
93 | 0xa5, 0x96, 0x94, 0xe7, 0x17, 0x65, 0x4b, 0x30, 0x29, 0x30, 0x6a, 0x70, 0x06, 0xc1, 0xb8, 0x20, | ||
94 | 0x99, 0xc4, 0x94, 0x94, 0xa2, 0xd4, 0xe2, 0x62, 0x09, 0x66, 0x88, 0x0c, 0x94, 0x6b, 0xe4, 0xcc, | ||
95 | 0xc5, 0xe5, 0x1e, 0x14, 0xe0, 0xec, 0x04, 0xb6, 0x5a, 0xc8, 0x94, 0x8b, 0x3b, 0xb8, 0x24, 0xb1, | ||
96 | 0xa8, 0x24, 0xb8, 0xa4, 0x28, 0x35, 0x31, 0x57, 0x48, 0x40, 0x0f, 0xe2, 0x08, 0x3d, 0x98, 0x0b, | ||
97 | 0xa4, 0x30, 0x44, 0x34, 0x18, 0x0d, 0x18, 0x9d, 0x38, 0xa2, 0xa0, 0xae, 0x4d, 0x62, 0x03, 0x3b, | ||
98 | 0xde, 0x18, 0x10, 0x00, 0x00, 0xff, 0xff, 0x10, 0x15, 0x39, 0x47, 0xd1, 0x00, 0x00, 0x00, | ||
99 | } | ||
100 | |||
71 | // Reference imports to suppress errors if they are not otherwise used. | 101 | // Reference imports to suppress errors if they are not otherwise used. |
72 | var _ context.Context | 102 | var _ context.Context |
73 | var _ grpc.ClientConn | 103 | var _ grpc.ClientConn |
@@ -76,8 +106,9 @@ var _ grpc.ClientConn | |||
76 | // is compatible with the grpc package it is being compiled against. | 106 | // is compatible with the grpc package it is being compiled against. |
77 | const _ = grpc.SupportPackageIsVersion4 | 107 | const _ = grpc.SupportPackageIsVersion4 |
78 | 108 | ||
79 | // Client API for GRPCBroker service | 109 | // GRPCBrokerClient is the client API for GRPCBroker service. |
80 | 110 | // | |
111 | // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. | ||
81 | type GRPCBrokerClient interface { | 112 | type GRPCBrokerClient interface { |
82 | StartStream(ctx context.Context, opts ...grpc.CallOption) (GRPCBroker_StartStreamClient, error) | 113 | StartStream(ctx context.Context, opts ...grpc.CallOption) (GRPCBroker_StartStreamClient, error) |
83 | } | 114 | } |
@@ -91,7 +122,7 @@ func NewGRPCBrokerClient(cc *grpc.ClientConn) GRPCBrokerClient { | |||
91 | } | 122 | } |
92 | 123 | ||
93 | func (c *gRPCBrokerClient) StartStream(ctx context.Context, opts ...grpc.CallOption) (GRPCBroker_StartStreamClient, error) { | 124 | func (c *gRPCBrokerClient) StartStream(ctx context.Context, opts ...grpc.CallOption) (GRPCBroker_StartStreamClient, error) { |
94 | stream, err := grpc.NewClientStream(ctx, &_GRPCBroker_serviceDesc.Streams[0], c.cc, "/plugin.GRPCBroker/StartStream", opts...) | 125 | stream, err := c.cc.NewStream(ctx, &_GRPCBroker_serviceDesc.Streams[0], "/plugin.GRPCBroker/StartStream", opts...) |
95 | if err != nil { | 126 | if err != nil { |
96 | return nil, err | 127 | return nil, err |
97 | } | 128 | } |
@@ -121,8 +152,7 @@ func (x *gRPCBrokerStartStreamClient) Recv() (*ConnInfo, error) { | |||
121 | return m, nil | 152 | return m, nil |
122 | } | 153 | } |
123 | 154 | ||
124 | // Server API for GRPCBroker service | 155 | // GRPCBrokerServer is the server API for GRPCBroker service. |
125 | |||
126 | type GRPCBrokerServer interface { | 156 | type GRPCBrokerServer interface { |
127 | StartStream(GRPCBroker_StartStreamServer) error | 157 | StartStream(GRPCBroker_StartStreamServer) error |
128 | } | 158 | } |
@@ -171,20 +201,3 @@ var _GRPCBroker_serviceDesc = grpc.ServiceDesc{ | |||
171 | }, | 201 | }, |
172 | Metadata: "grpc_broker.proto", | 202 | Metadata: "grpc_broker.proto", |
173 | } | 203 | } |
174 | |||
175 | func init() { proto.RegisterFile("grpc_broker.proto", fileDescriptor0) } | ||
176 | |||
177 | var fileDescriptor0 = []byte{ | ||
178 | // 170 bytes of a gzipped FileDescriptorProto | ||
179 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x4c, 0x2f, 0x2a, 0x48, | ||
180 | 0x8e, 0x4f, 0x2a, 0xca, 0xcf, 0x4e, 0x2d, 0xd2, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x2b, | ||
181 | 0xc8, 0x29, 0x4d, 0xcf, 0xcc, 0x53, 0x8a, 0xe5, 0xe2, 0x70, 0xce, 0xcf, 0xcb, 0xf3, 0xcc, 0x4b, | ||
182 | 0xcb, 0x17, 0x92, 0xe5, 0xe2, 0x2a, 0x4e, 0x2d, 0x2a, 0xcb, 0x4c, 0x4e, 0x8d, 0xcf, 0x4c, 0x91, | ||
183 | 0x60, 0x54, 0x60, 0xd4, 0xe0, 0x0d, 0xe2, 0x84, 0x8a, 0x78, 0xa6, 0x08, 0x49, 0x70, 0xb1, 0xe7, | ||
184 | 0xa5, 0x96, 0x94, 0xe7, 0x17, 0x65, 0x4b, 0x30, 0x29, 0x30, 0x6a, 0x70, 0x06, 0xc1, 0xb8, 0x20, | ||
185 | 0x99, 0xc4, 0x94, 0x94, 0xa2, 0xd4, 0xe2, 0x62, 0x09, 0x66, 0x88, 0x0c, 0x94, 0x6b, 0xe4, 0xcc, | ||
186 | 0xc5, 0xe5, 0x1e, 0x14, 0xe0, 0xec, 0x04, 0xb6, 0x5a, 0xc8, 0x94, 0x8b, 0x3b, 0xb8, 0x24, 0xb1, | ||
187 | 0xa8, 0x24, 0xb8, 0xa4, 0x28, 0x35, 0x31, 0x57, 0x48, 0x40, 0x0f, 0xe2, 0x08, 0x3d, 0x98, 0x0b, | ||
188 | 0xa4, 0x30, 0x44, 0x34, 0x18, 0x0d, 0x18, 0x93, 0xd8, 0xc0, 0x4e, 0x36, 0x06, 0x04, 0x00, 0x00, | ||
189 | 0xff, 0xff, 0x7b, 0x5d, 0xfb, 0xe1, 0xc7, 0x00, 0x00, 0x00, | ||
190 | } | ||
diff --git a/vendor/github.com/hashicorp/go-plugin/grpc_broker.proto b/vendor/github.com/hashicorp/go-plugin/internal/plugin/grpc_broker.proto index f578348..3fa79e8 100644 --- a/vendor/github.com/hashicorp/go-plugin/grpc_broker.proto +++ b/vendor/github.com/hashicorp/go-plugin/internal/plugin/grpc_broker.proto | |||
@@ -1,5 +1,6 @@ | |||
1 | syntax = "proto3"; | 1 | syntax = "proto3"; |
2 | package plugin; | 2 | package plugin; |
3 | option go_package = "plugin"; | ||
3 | 4 | ||
4 | message ConnInfo { | 5 | message ConnInfo { |
5 | uint32 service_id = 1; | 6 | uint32 service_id = 1; |
diff --git a/vendor/github.com/hashicorp/go-plugin/internal/plugin/grpc_controller.pb.go b/vendor/github.com/hashicorp/go-plugin/internal/plugin/grpc_controller.pb.go new file mode 100644 index 0000000..38b4204 --- /dev/null +++ b/vendor/github.com/hashicorp/go-plugin/internal/plugin/grpc_controller.pb.go | |||
@@ -0,0 +1,143 @@ | |||
1 | // Code generated by protoc-gen-go. DO NOT EDIT. | ||
2 | // source: grpc_controller.proto | ||
3 | |||
4 | package plugin | ||
5 | |||
6 | import ( | ||
7 | fmt "fmt" | ||
8 | proto "github.com/golang/protobuf/proto" | ||
9 | context "golang.org/x/net/context" | ||
10 | grpc "google.golang.org/grpc" | ||
11 | math "math" | ||
12 | ) | ||
13 | |||
14 | // Reference imports to suppress errors if they are not otherwise used. | ||
15 | var _ = proto.Marshal | ||
16 | var _ = fmt.Errorf | ||
17 | var _ = math.Inf | ||
18 | |||
19 | // This is a compile-time assertion to ensure that this generated file | ||
20 | // is compatible with the proto package it is being compiled against. | ||
21 | // A compilation error at this line likely means your copy of the | ||
22 | // proto package needs to be updated. | ||
23 | const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package | ||
24 | |||
25 | type Empty struct { | ||
26 | XXX_NoUnkeyedLiteral struct{} `json:"-"` | ||
27 | XXX_unrecognized []byte `json:"-"` | ||
28 | XXX_sizecache int32 `json:"-"` | ||
29 | } | ||
30 | |||
31 | func (m *Empty) Reset() { *m = Empty{} } | ||
32 | func (m *Empty) String() string { return proto.CompactTextString(m) } | ||
33 | func (*Empty) ProtoMessage() {} | ||
34 | func (*Empty) Descriptor() ([]byte, []int) { | ||
35 | return fileDescriptor_23c2c7e42feab570, []int{0} | ||
36 | } | ||
37 | |||
38 | func (m *Empty) XXX_Unmarshal(b []byte) error { | ||
39 | return xxx_messageInfo_Empty.Unmarshal(m, b) | ||
40 | } | ||
41 | func (m *Empty) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { | ||
42 | return xxx_messageInfo_Empty.Marshal(b, m, deterministic) | ||
43 | } | ||
44 | func (m *Empty) XXX_Merge(src proto.Message) { | ||
45 | xxx_messageInfo_Empty.Merge(m, src) | ||
46 | } | ||
47 | func (m *Empty) XXX_Size() int { | ||
48 | return xxx_messageInfo_Empty.Size(m) | ||
49 | } | ||
50 | func (m *Empty) XXX_DiscardUnknown() { | ||
51 | xxx_messageInfo_Empty.DiscardUnknown(m) | ||
52 | } | ||
53 | |||
54 | var xxx_messageInfo_Empty proto.InternalMessageInfo | ||
55 | |||
56 | func init() { | ||
57 | proto.RegisterType((*Empty)(nil), "plugin.Empty") | ||
58 | } | ||
59 | |||
60 | func init() { proto.RegisterFile("grpc_controller.proto", fileDescriptor_23c2c7e42feab570) } | ||
61 | |||
62 | var fileDescriptor_23c2c7e42feab570 = []byte{ | ||
63 | // 108 bytes of a gzipped FileDescriptorProto | ||
64 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x4d, 0x2f, 0x2a, 0x48, | ||
65 | 0x8e, 0x4f, 0xce, 0xcf, 0x2b, 0x29, 0xca, 0xcf, 0xc9, 0x49, 0x2d, 0xd2, 0x2b, 0x28, 0xca, 0x2f, | ||
66 | 0xc9, 0x17, 0x62, 0x2b, 0xc8, 0x29, 0x4d, 0xcf, 0xcc, 0x53, 0x62, 0xe7, 0x62, 0x75, 0xcd, 0x2d, | ||
67 | 0x28, 0xa9, 0x34, 0xb2, 0xe2, 0xe2, 0x73, 0x0f, 0x0a, 0x70, 0x76, 0x86, 0x2b, 0x14, 0xd2, 0xe0, | ||
68 | 0xe2, 0x08, 0xce, 0x28, 0x2d, 0x49, 0xc9, 0x2f, 0xcf, 0x13, 0xe2, 0xd5, 0x83, 0xa8, 0xd7, 0x03, | ||
69 | 0x2b, 0x96, 0x42, 0xe5, 0x3a, 0x71, 0x44, 0x41, 0x8d, 0x4b, 0x62, 0x03, 0x9b, 0x6e, 0x0c, 0x08, | ||
70 | 0x00, 0x00, 0xff, 0xff, 0xab, 0x7c, 0x27, 0xe5, 0x76, 0x00, 0x00, 0x00, | ||
71 | } | ||
72 | |||
73 | // Reference imports to suppress errors if they are not otherwise used. | ||
74 | var _ context.Context | ||
75 | var _ grpc.ClientConn | ||
76 | |||
77 | // This is a compile-time assertion to ensure that this generated file | ||
78 | // is compatible with the grpc package it is being compiled against. | ||
79 | const _ = grpc.SupportPackageIsVersion4 | ||
80 | |||
81 | // GRPCControllerClient is the client API for GRPCController service. | ||
82 | // | ||
83 | // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. | ||
84 | type GRPCControllerClient interface { | ||
85 | Shutdown(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*Empty, error) | ||
86 | } | ||
87 | |||
88 | type gRPCControllerClient struct { | ||
89 | cc *grpc.ClientConn | ||
90 | } | ||
91 | |||
92 | func NewGRPCControllerClient(cc *grpc.ClientConn) GRPCControllerClient { | ||
93 | return &gRPCControllerClient{cc} | ||
94 | } | ||
95 | |||
96 | func (c *gRPCControllerClient) Shutdown(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*Empty, error) { | ||
97 | out := new(Empty) | ||
98 | err := c.cc.Invoke(ctx, "/plugin.GRPCController/Shutdown", in, out, opts...) | ||
99 | if err != nil { | ||
100 | return nil, err | ||
101 | } | ||
102 | return out, nil | ||
103 | } | ||
104 | |||
105 | // GRPCControllerServer is the server API for GRPCController service. | ||
106 | type GRPCControllerServer interface { | ||
107 | Shutdown(context.Context, *Empty) (*Empty, error) | ||
108 | } | ||
109 | |||
110 | func RegisterGRPCControllerServer(s *grpc.Server, srv GRPCControllerServer) { | ||
111 | s.RegisterService(&_GRPCController_serviceDesc, srv) | ||
112 | } | ||
113 | |||
114 | func _GRPCController_Shutdown_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { | ||
115 | in := new(Empty) | ||
116 | if err := dec(in); err != nil { | ||
117 | return nil, err | ||
118 | } | ||
119 | if interceptor == nil { | ||
120 | return srv.(GRPCControllerServer).Shutdown(ctx, in) | ||
121 | } | ||
122 | info := &grpc.UnaryServerInfo{ | ||
123 | Server: srv, | ||
124 | FullMethod: "/plugin.GRPCController/Shutdown", | ||
125 | } | ||
126 | handler := func(ctx context.Context, req interface{}) (interface{}, error) { | ||
127 | return srv.(GRPCControllerServer).Shutdown(ctx, req.(*Empty)) | ||
128 | } | ||
129 | return interceptor(ctx, in, info, handler) | ||
130 | } | ||
131 | |||
132 | var _GRPCController_serviceDesc = grpc.ServiceDesc{ | ||
133 | ServiceName: "plugin.GRPCController", | ||
134 | HandlerType: (*GRPCControllerServer)(nil), | ||
135 | Methods: []grpc.MethodDesc{ | ||
136 | { | ||
137 | MethodName: "Shutdown", | ||
138 | Handler: _GRPCController_Shutdown_Handler, | ||
139 | }, | ||
140 | }, | ||
141 | Streams: []grpc.StreamDesc{}, | ||
142 | Metadata: "grpc_controller.proto", | ||
143 | } | ||
diff --git a/vendor/github.com/hashicorp/go-plugin/internal/plugin/grpc_controller.proto b/vendor/github.com/hashicorp/go-plugin/internal/plugin/grpc_controller.proto new file mode 100644 index 0000000..345d0a1 --- /dev/null +++ b/vendor/github.com/hashicorp/go-plugin/internal/plugin/grpc_controller.proto | |||
@@ -0,0 +1,11 @@ | |||
1 | syntax = "proto3"; | ||
2 | package plugin; | ||
3 | option go_package = "plugin"; | ||
4 | |||
5 | message Empty { | ||
6 | } | ||
7 | |||
8 | // The GRPCController is responsible for telling the plugin server to shutdown. | ||
9 | service GRPCController { | ||
10 | rpc Shutdown(Empty) returns (Empty); | ||
11 | } | ||
diff --git a/vendor/github.com/hashicorp/go-plugin/log_entry.go b/vendor/github.com/hashicorp/go-plugin/log_entry.go index 2996c14..fb2ef93 100644 --- a/vendor/github.com/hashicorp/go-plugin/log_entry.go +++ b/vendor/github.com/hashicorp/go-plugin/log_entry.go | |||
@@ -32,11 +32,11 @@ func flattenKVPairs(kvs []*logEntryKV) []interface{} { | |||
32 | } | 32 | } |
33 | 33 | ||
34 | // parseJSON handles parsing JSON output | 34 | // parseJSON handles parsing JSON output |
35 | func parseJSON(input string) (*logEntry, error) { | 35 | func parseJSON(input []byte) (*logEntry, error) { |
36 | var raw map[string]interface{} | 36 | var raw map[string]interface{} |
37 | entry := &logEntry{} | 37 | entry := &logEntry{} |
38 | 38 | ||
39 | err := json.Unmarshal([]byte(input), &raw) | 39 | err := json.Unmarshal(input, &raw) |
40 | if err != nil { | 40 | if err != nil { |
41 | return nil, err | 41 | return nil, err |
42 | } | 42 | } |
diff --git a/vendor/github.com/hashicorp/go-plugin/mtls.go b/vendor/github.com/hashicorp/go-plugin/mtls.go new file mode 100644 index 0000000..8895524 --- /dev/null +++ b/vendor/github.com/hashicorp/go-plugin/mtls.go | |||
@@ -0,0 +1,73 @@ | |||
1 | package plugin | ||
2 | |||
3 | import ( | ||
4 | "bytes" | ||
5 | "crypto/ecdsa" | ||
6 | "crypto/elliptic" | ||
7 | "crypto/rand" | ||
8 | "crypto/x509" | ||
9 | "crypto/x509/pkix" | ||
10 | "encoding/pem" | ||
11 | "math/big" | ||
12 | "time" | ||
13 | ) | ||
14 | |||
15 | // generateCert generates a temporary certificate for plugin authentication. The | ||
16 | // certificate and private key are returns in PEM format. | ||
17 | func generateCert() (cert []byte, privateKey []byte, err error) { | ||
18 | key, err := ecdsa.GenerateKey(elliptic.P521(), rand.Reader) | ||
19 | if err != nil { | ||
20 | return nil, nil, err | ||
21 | } | ||
22 | |||
23 | serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) | ||
24 | sn, err := rand.Int(rand.Reader, serialNumberLimit) | ||
25 | if err != nil { | ||
26 | return nil, nil, err | ||
27 | } | ||
28 | |||
29 | host := "localhost" | ||
30 | |||
31 | template := &x509.Certificate{ | ||
32 | Subject: pkix.Name{ | ||
33 | CommonName: host, | ||
34 | Organization: []string{"HashiCorp"}, | ||
35 | }, | ||
36 | DNSNames: []string{host}, | ||
37 | ExtKeyUsage: []x509.ExtKeyUsage{ | ||
38 | x509.ExtKeyUsageClientAuth, | ||
39 | x509.ExtKeyUsageServerAuth, | ||
40 | }, | ||
41 | KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment | x509.KeyUsageKeyAgreement | x509.KeyUsageCertSign, | ||
42 | BasicConstraintsValid: true, | ||
43 | SerialNumber: sn, | ||
44 | NotBefore: time.Now().Add(-30 * time.Second), | ||
45 | NotAfter: time.Now().Add(262980 * time.Hour), | ||
46 | IsCA: true, | ||
47 | } | ||
48 | |||
49 | der, err := x509.CreateCertificate(rand.Reader, template, template, key.Public(), key) | ||
50 | if err != nil { | ||
51 | return nil, nil, err | ||
52 | } | ||
53 | |||
54 | var certOut bytes.Buffer | ||
55 | if err := pem.Encode(&certOut, &pem.Block{Type: "CERTIFICATE", Bytes: der}); err != nil { | ||
56 | return nil, nil, err | ||
57 | } | ||
58 | |||
59 | keyBytes, err := x509.MarshalECPrivateKey(key) | ||
60 | if err != nil { | ||
61 | return nil, nil, err | ||
62 | } | ||
63 | |||
64 | var keyOut bytes.Buffer | ||
65 | if err := pem.Encode(&keyOut, &pem.Block{Type: "EC PRIVATE KEY", Bytes: keyBytes}); err != nil { | ||
66 | return nil, nil, err | ||
67 | } | ||
68 | |||
69 | cert = certOut.Bytes() | ||
70 | privateKey = keyOut.Bytes() | ||
71 | |||
72 | return cert, privateKey, nil | ||
73 | } | ||
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 | ||
3 | import ( | 3 | import ( |
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. | ||
56 | type PluginSet map[string]Plugin | ||
57 | |||
49 | // ServeConfig configures what sorts of plugins are served. | 58 | // ServeConfig configures what sorts of plugins are served. |
50 | type ServeConfig struct { | 59 | type 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 |
76 | func (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 { | 93 | func 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 |
diff --git a/vendor/github.com/hashicorp/go-plugin/testing.go b/vendor/github.com/hashicorp/go-plugin/testing.go index df29593..2cf2c26 100644 --- a/vendor/github.com/hashicorp/go-plugin/testing.go +++ b/vendor/github.com/hashicorp/go-plugin/testing.go | |||
@@ -3,13 +3,28 @@ package plugin | |||
3 | import ( | 3 | import ( |
4 | "bytes" | 4 | "bytes" |
5 | "context" | 5 | "context" |
6 | "io" | ||
6 | "net" | 7 | "net" |
7 | "net/rpc" | 8 | "net/rpc" |
8 | 9 | ||
9 | "github.com/mitchellh/go-testing-interface" | 10 | "github.com/mitchellh/go-testing-interface" |
11 | hclog "github.com/hashicorp/go-hclog" | ||
12 | "github.com/hashicorp/go-plugin/internal/plugin" | ||
10 | "google.golang.org/grpc" | 13 | "google.golang.org/grpc" |
11 | ) | 14 | ) |
12 | 15 | ||
16 | // TestOptions allows specifying options that can affect the behavior of the | ||
17 | // test functions | ||
18 | type TestOptions struct { | ||
19 | //ServerStdout causes the given value to be used in place of a blank buffer | ||
20 | //for RPCServer's Stdout | ||
21 | ServerStdout io.ReadCloser | ||
22 | |||
23 | //ServerStderr causes the given value to be used in place of a blank buffer | ||
24 | //for RPCServer's Stderr | ||
25 | ServerStderr io.ReadCloser | ||
26 | } | ||
27 | |||
13 | // The testing file contains test helpers that you can use outside of | 28 | // The testing file contains test helpers that you can use outside of |
14 | // this package for making it easier to test plugins themselves. | 29 | // this package for making it easier to test plugins themselves. |
15 | 30 | ||
@@ -61,12 +76,20 @@ func TestRPCConn(t testing.T) (*rpc.Client, *rpc.Server) { | |||
61 | 76 | ||
62 | // TestPluginRPCConn returns a plugin RPC client and server that are connected | 77 | // TestPluginRPCConn returns a plugin RPC client and server that are connected |
63 | // together and configured. | 78 | // together and configured. |
64 | func TestPluginRPCConn(t testing.T, ps map[string]Plugin) (*RPCClient, *RPCServer) { | 79 | func TestPluginRPCConn(t testing.T, ps map[string]Plugin, opts *TestOptions) (*RPCClient, *RPCServer) { |
65 | // Create two net.Conns we can use to shuttle our control connection | 80 | // Create two net.Conns we can use to shuttle our control connection |
66 | clientConn, serverConn := TestConn(t) | 81 | clientConn, serverConn := TestConn(t) |
67 | 82 | ||
68 | // Start up the server | 83 | // Start up the server |
69 | server := &RPCServer{Plugins: ps, Stdout: new(bytes.Buffer), Stderr: new(bytes.Buffer)} | 84 | server := &RPCServer{Plugins: ps, Stdout: new(bytes.Buffer), Stderr: new(bytes.Buffer)} |
85 | if opts != nil { | ||
86 | if opts.ServerStdout != nil { | ||
87 | server.Stdout = opts.ServerStdout | ||
88 | } | ||
89 | if opts.ServerStderr != nil { | ||
90 | server.Stderr = opts.ServerStderr | ||
91 | } | ||
92 | } | ||
70 | go server.ServeConn(serverConn) | 93 | go server.ServeConn(serverConn) |
71 | 94 | ||
72 | // Connect the client to the server | 95 | // Connect the client to the server |
@@ -119,9 +142,11 @@ func TestPluginGRPCConn(t testing.T, ps map[string]Plugin) (*GRPCClient, *GRPCSe | |||
119 | // Start up the server | 142 | // Start up the server |
120 | server := &GRPCServer{ | 143 | server := &GRPCServer{ |
121 | Plugins: ps, | 144 | Plugins: ps, |
145 | DoneCh: make(chan struct{}), | ||
122 | Server: DefaultGRPCServer, | 146 | Server: DefaultGRPCServer, |
123 | Stdout: new(bytes.Buffer), | 147 | Stdout: new(bytes.Buffer), |
124 | Stderr: new(bytes.Buffer), | 148 | Stderr: new(bytes.Buffer), |
149 | logger: hclog.Default(), | ||
125 | } | 150 | } |
126 | if err := server.Init(); err != nil { | 151 | if err := server.Init(); err != nil { |
127 | t.Fatalf("err: %s", err) | 152 | t.Fatalf("err: %s", err) |
@@ -144,10 +169,11 @@ func TestPluginGRPCConn(t testing.T, ps map[string]Plugin) (*GRPCClient, *GRPCSe | |||
144 | 169 | ||
145 | // Create the client | 170 | // Create the client |
146 | client := &GRPCClient{ | 171 | client := &GRPCClient{ |
147 | Conn: conn, | 172 | Conn: conn, |
148 | Plugins: ps, | 173 | Plugins: ps, |
149 | broker: broker, | 174 | broker: broker, |
150 | doneCtx: context.Background(), | 175 | doneCtx: context.Background(), |
176 | controller: plugin.NewGRPCControllerClient(conn), | ||
151 | } | 177 | } |
152 | 178 | ||
153 | return client, server | 179 | return client, server |