Skip to content
This repository was archived by the owner on Jan 8, 2024. It is now read-only.

Commit 3fe0ec4

Browse files
authored
Merge pull request #1842 from hashicorp/backport/debug-plugin/presently-integral-jennet
Backport of Feature: plugin debugging into release/0.4.x
2 parents 9e699ec + abb1e3b commit 3fe0ec4

File tree

7 files changed

+182
-10
lines changed

7 files changed

+182
-10
lines changed

Diff for: .changelog/1716.txt

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
```release-note:feature
2+
plugin: Allow debugging of plugins with tools like delve
3+
```
4+

Diff for: go.mod

+2-2
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ require (
5050
github.com/hashicorp/go-hclog v0.14.1
5151
github.com/hashicorp/go-memdb v1.3.2
5252
github.com/hashicorp/go-multierror v1.1.0
53-
github.com/hashicorp/go-plugin v1.3.0
53+
github.com/hashicorp/go-plugin v1.4.2
5454
github.com/hashicorp/go-uuid v1.0.2
5555
github.com/hashicorp/go-version v1.2.0
5656
github.com/hashicorp/hcl/v2 v2.10.1-0.20210621220818-327f3ce2570e
@@ -59,7 +59,7 @@ require (
5959
github.com/hashicorp/vault/api v1.0.5-0.20200519221902-385fac77e20f
6060
github.com/hashicorp/vault/sdk v0.1.14-0.20201202172114-ee5ebeb30fef
6161
github.com/hashicorp/waypoint-hzn v0.0.0-20201008221232-97cd4d9120b9
62-
github.com/hashicorp/waypoint-plugin-sdk v0.0.0-20210609145036-5c5b44751ee6
62+
github.com/hashicorp/waypoint-plugin-sdk v0.0.0-20210625180209-eda7ae600c2d
6363
github.com/imdario/mergo v0.3.11
6464
github.com/improbable-eng/grpc-web v0.13.0
6565
github.com/kevinburke/go-bindata v3.22.0+incompatible

Diff for: go.sum

+4-4
Original file line numberDiff line numberDiff line change
@@ -822,8 +822,8 @@ github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHh
822822
github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI=
823823
github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
824824
github.com/hashicorp/go-plugin v1.0.1/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY=
825-
github.com/hashicorp/go-plugin v1.3.0 h1:4d/wJojzvHV1I4i/rrjVaeuyxWrLzDE1mDCyDy8fXS8=
826-
github.com/hashicorp/go-plugin v1.3.0/go.mod h1:F9eH4LrE/ZsRdbwhfjs9k9HoDUwAHnYtXdgmf1AVNs0=
825+
github.com/hashicorp/go-plugin v1.4.2 h1:yFvG3ufXXpqiMiZx9HLcaK3XbIqQ1WJFR/F1a2CuVw0=
826+
github.com/hashicorp/go-plugin v1.4.2/go.mod h1:5fGEH17QVwTTcR0zV7yhDPLLmFX9YSZ38b18Udy6vYQ=
827827
github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
828828
github.com/hashicorp/go-retryablehttp v0.5.4/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
829829
github.com/hashicorp/go-retryablehttp v0.6.2/go.mod h1:gEx6HMUGxYYhJScX7W1Il64m6cc2C1mDaW3NQ9sY1FY=
@@ -882,8 +882,8 @@ github.com/hashicorp/vault/sdk v0.1.14-0.20201202172114-ee5ebeb30fef h1:YKouRHFf
882882
github.com/hashicorp/vault/sdk v0.1.14-0.20201202172114-ee5ebeb30fef/go.mod h1:cAGI4nVnEfAyMeqt9oB+Mase8DNn3qA/LDNHURiwssY=
883883
github.com/hashicorp/waypoint-hzn v0.0.0-20201008221232-97cd4d9120b9 h1:i9hzlv2SpmaNcQ8ZLGn01fp2Gqyejj0juVs7rYDgecE=
884884
github.com/hashicorp/waypoint-hzn v0.0.0-20201008221232-97cd4d9120b9/go.mod h1:ObgQSWSX9rsNofh16kctm6XxLW2QW1Ay6/9ris6T6DU=
885-
github.com/hashicorp/waypoint-plugin-sdk v0.0.0-20210609145036-5c5b44751ee6 h1:zhcfxphKiDYtZHmtgl4YC4rhNxIzv0aJmcz2fejJT2g=
886-
github.com/hashicorp/waypoint-plugin-sdk v0.0.0-20210609145036-5c5b44751ee6/go.mod h1:C6CXoZZFHsW8wb6WV6pIKZ5KFwd7XgK4GRD3hkt+lfg=
885+
github.com/hashicorp/waypoint-plugin-sdk v0.0.0-20210625180209-eda7ae600c2d h1:+ekQ8zfw9gM28KpRGXfEdrlR/JT8p4AiexfoBh+3bvE=
886+
github.com/hashicorp/waypoint-plugin-sdk v0.0.0-20210625180209-eda7ae600c2d/go.mod h1:l5rxDV4JfLCnMb/+0DxIjE40tHXPWbDyerz+f2Oul3I=
887887
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
888888
github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
889889
github.com/hashicorp/yamux v0.0.0-20190923154419-df201c70410d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=

Diff for: internal/cli/plugin.go

+43-3
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,65 @@
11
package cli
22

33
import (
4+
"context"
5+
"fmt"
46
"github.com/hashicorp/waypoint-plugin-sdk"
7+
"github.com/hashicorp/waypoint/internal/pkg/flag"
58
"github.com/hashicorp/waypoint/internal/plugin"
69
)
710

811
type PluginCommand struct {
912
*baseCommand
13+
debugMode bool
1014
}
1115

1216
func (c *PluginCommand) Run(args []string) int {
13-
plugin, ok := plugin.Builtins[args[0]]
17+
flags := c.Flags()
18+
19+
// Initialize. If we fail, we just exit since Init handles the UI.
20+
if err := c.Init(
21+
WithArgs(args),
22+
WithFlags(flags),
23+
WithClient(false),
24+
WithNoAutoServer(),
25+
WithNoConfig(),
26+
); err != nil {
27+
return 1
28+
}
29+
args = flags.Args()
30+
31+
pluginName := args[0]
32+
33+
plugin, ok := plugin.Builtins[pluginName]
1434
if !ok {
15-
panic("no such plugin: " + args[0])
35+
panic("no such plugin: " + pluginName)
1636
}
1737

1838
// Run the plugin
19-
sdk.Main(plugin...)
39+
if !c.debugMode {
40+
sdk.Main(plugin...)
41+
} else {
42+
err := sdk.Debug(context.Background(), pluginName, plugin...)
43+
if err != nil {
44+
panic(fmt.Sprintf("Failed to launch plugin in debug mode: %s", err))
45+
}
46+
}
47+
2048
return 0
2149
}
2250

51+
func (c *PluginCommand) Flags() *flag.Sets {
52+
return c.flagSet(0, func(set *flag.Sets) {
53+
f := set.NewSet("Command Options")
54+
f.BoolVar(&flag.BoolVar{
55+
Name: "debug",
56+
Default: false,
57+
Target: &c.debugMode,
58+
Usage: "set to true to run the plugin with support for debuggers like delve",
59+
})
60+
})
61+
}
62+
2363
func (c *PluginCommand) Synopsis() string {
2464
return "Execute a built-in plugin."
2565
}

Diff for: internal/client/server.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package client
22

33
import (
44
"context"
5+
"fmt"
56
"io"
67
"net"
78
"path/filepath"
@@ -93,7 +94,7 @@ func (c *Project) initLocalServer(ctx context.Context) (*grpc.ClientConn, error)
9394
Timeout: 1 * time.Second,
9495
})
9596
if err != nil {
96-
return nil, err
97+
return nil, fmt.Errorf("failed opening boltdb path %s. Is another server already running against this db?: %w", path, err)
9798
}
9899
closers = append(closers, db)
99100

Diff for: internal/plugin/factory.go

+60
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package plugin
22

33
import (
4+
"fmt"
45
"os"
56
"os/exec"
67
"runtime"
@@ -95,6 +96,65 @@ func BuiltinFactory(name string, typ component.Type) interface{} {
9596
return Factory(cmd, typ)
9697
}
9798

99+
// ReattachPluginFactory produces a provider factory that uses the passed
100+
// reattach information to connect to go-plugin processes that are already
101+
// running, and implements Instance against it.
102+
func ReattachPluginFactory(reattach *plugin.ReattachConfig, typ component.Type) interface{} {
103+
return func(log hclog.Logger) (interface{}, error) {
104+
config := pluginclient.ClientConfig(log)
105+
config.Logger = log
106+
config.Reattach = reattach
107+
108+
// Verify that we know about the requested plugin's protocol version
109+
plugins, ok := config.VersionedPlugins[reattach.ProtocolVersion]
110+
if !ok {
111+
err := fmt.Errorf("no plugins found for requested protocol version number %d", reattach.ProtocolVersion)
112+
log.Error(err.Error())
113+
return Instance{}, err
114+
}
115+
config.Plugins = plugins
116+
117+
// Log that we're going to launch this
118+
log.Info("Connecting to a reattach plugin", "type", typ, "Addr", reattach.Addr.String())
119+
120+
// Connect to the plugin
121+
client := plugin.NewClient(config)
122+
rpcClient, err := client.Client()
123+
if err != nil {
124+
log.Error("error creating reattach plugin client", "err", err)
125+
client.Kill()
126+
return nil, err
127+
}
128+
129+
// Request the plugin. We don't request the mapper type because
130+
// we handle that below.
131+
var raw interface{}
132+
if typ != component.MapperType {
133+
raw, err = rpcClient.Dispense(strings.ToLower(typ.String()))
134+
if err != nil {
135+
log.Error("error requesting reattach plugin", "type", typ, "err", err)
136+
client.Kill()
137+
return nil, err
138+
}
139+
}
140+
141+
// Request the mappers
142+
mappers, err := pluginclient.Mappers(client)
143+
if err != nil {
144+
log.Error("error requesting reattach plugin mappers", "err", err)
145+
client.Kill()
146+
return nil, err
147+
}
148+
149+
log.Debug("successfully reattached to a plugin")
150+
return &Instance{
151+
Component: raw,
152+
Mappers: mappers,
153+
Close: func() { client.Kill() },
154+
}, nil
155+
}
156+
}
157+
98158
// Instance is the result generated by the factory. This lets us pack
99159
// a bit more information into plugin-launched components.
100160
type Instance struct {

Diff for: internal/runner/operation.go

+67
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,22 @@ package runner
22

33
import (
44
"context"
5+
"encoding/json"
56
"fmt"
67
"io/ioutil"
8+
"net"
9+
"os"
710
"path/filepath"
811
"reflect"
12+
"strings"
913

1014
"github.com/hashicorp/go-hclog"
1115
"github.com/hashicorp/go-multierror"
16+
goplugin "github.com/hashicorp/go-plugin"
1217
"google.golang.org/grpc/codes"
1318
"google.golang.org/grpc/status"
1419

20+
sdk "github.com/hashicorp/waypoint-plugin-sdk"
1521
"github.com/hashicorp/waypoint-plugin-sdk/component"
1622
"github.com/hashicorp/waypoint-plugin-sdk/datadir"
1723
"github.com/hashicorp/waypoint-plugin-sdk/terminal"
@@ -225,12 +231,33 @@ func (r *Runner) pluginFactories(
225231
}
226232
log.Debug("plugin search path", "path", pluginPaths)
227233

234+
// Look for any reattach plugins
235+
var reattachPluginConfigs map[string]*goplugin.ReattachConfig
236+
reattachPluginsStr := os.Getenv("WP_REATTACH_PLUGINS")
237+
if reattachPluginsStr != "" {
238+
var err error
239+
reattachPluginConfigs, err = parseReattachPlugins(reattachPluginsStr)
240+
if err != nil {
241+
return nil, err
242+
}
243+
}
244+
228245
// Search for all of our plugins
229246
var perr error
230247
for _, pluginCfg := range plugins {
231248
plog := log.With("plugin_name", pluginCfg.Name)
232249
plog.Debug("searching for plugin")
233250

251+
if reattachConfig, ok := reattachPluginConfigs[pluginCfg.Name]; ok {
252+
plog.Debug(fmt.Sprintf("plugin %s is declared as running for reattachment", pluginCfg.Name))
253+
for _, t := range pluginCfg.Types() {
254+
if err := result[t].Register(pluginCfg.Name, plugin.ReattachPluginFactory(reattachConfig, t)); err != nil {
255+
return nil, err
256+
}
257+
}
258+
continue
259+
}
260+
234261
// Find our plugin.
235262
cmd, err := plugin.Discover(pluginCfg, pluginPaths)
236263
if err != nil {
@@ -267,6 +294,46 @@ func (r *Runner) pluginFactories(
267294
return result, perr
268295
}
269296

297+
// parse information on reattaching to plugins out of a
298+
// JSON-encoded environment variable.
299+
func parseReattachPlugins(in string) (map[string]*goplugin.ReattachConfig, error) {
300+
reattachConfigs := map[string]*goplugin.ReattachConfig{}
301+
if in != "" {
302+
in = strings.TrimRight(in, "'")
303+
in = strings.TrimLeft(in, "'")
304+
var m map[string]sdk.ReattachConfig
305+
err := json.Unmarshal([]byte(in), &m)
306+
if err != nil {
307+
return reattachConfigs, fmt.Errorf("Invalid format for WP_REATTACH_PROVIDERS: %w", err)
308+
}
309+
for p, c := range m {
310+
var addr net.Addr
311+
switch c.Addr.Network {
312+
case "unix":
313+
addr, err = net.ResolveUnixAddr("unix", c.Addr.String)
314+
if err != nil {
315+
return reattachConfigs, fmt.Errorf("Invalid unix socket path %q for %q: %w", c.Addr.String, p, err)
316+
}
317+
case "tcp":
318+
addr, err = net.ResolveTCPAddr("tcp", c.Addr.String)
319+
if err != nil {
320+
return reattachConfigs, fmt.Errorf("Invalid TCP address %q for %q: %w", c.Addr.String, p, err)
321+
}
322+
default:
323+
return reattachConfigs, fmt.Errorf("Unknown address type %q for %q", c.Addr.String, p)
324+
}
325+
reattachConfigs[p] = &goplugin.ReattachConfig{
326+
Protocol: goplugin.Protocol(c.Protocol),
327+
ProtocolVersion: c.ProtocolVersion,
328+
Pid: c.Pid,
329+
Test: c.Test,
330+
Addr: addr,
331+
}
332+
}
333+
}
334+
return reattachConfigs, nil
335+
}
336+
270337
// operationNoDataFunc is the function type for operations that are
271338
// executed without data downloaded.
272339
type operationNoDataFunc func(*Runner, context.Context, hclog.Logger, *pb.Job) (*pb.Job_Result, error)

0 commit comments

Comments
 (0)