github.com/hashicorp/terraform-plugin-sdk@v1.17.2/plugin/debug.go (about) 1 package plugin 2 3 import ( 4 "context" 5 "encoding/json" 6 "errors" 7 "fmt" 8 "os" 9 "os/signal" 10 "time" 11 12 "github.com/hashicorp/go-plugin" 13 ) 14 15 // ReattachConfig holds the information Terraform needs to be able to attach 16 // itself to a provider process, so it can drive the process. 17 type ReattachConfig struct { 18 Protocol string 19 Pid int 20 Test bool 21 Addr ReattachConfigAddr 22 } 23 24 // ReattachConfigAddr is a JSON-encoding friendly version of net.Addr. 25 type ReattachConfigAddr struct { 26 Network string 27 String string 28 } 29 30 // DebugServe starts a plugin server in debug mode; this should only be used 31 // when the provider will manage its own lifecycle. It is not recommended for 32 // normal usage; Serve is the correct function for that. 33 func DebugServe(ctx context.Context, opts *ServeOpts) (ReattachConfig, <-chan struct{}, error) { 34 reattachCh := make(chan *plugin.ReattachConfig) 35 closeCh := make(chan struct{}) 36 37 opts.TestConfig = &plugin.ServeTestConfig{ 38 Context: ctx, 39 ReattachConfigCh: reattachCh, 40 CloseCh: closeCh, 41 } 42 43 go Serve(opts) 44 45 var config *plugin.ReattachConfig 46 select { 47 case config = <-reattachCh: 48 case <-time.After(2 * time.Second): 49 return ReattachConfig{}, closeCh, errors.New("timeout waiting on reattach config") 50 } 51 52 if config == nil { 53 return ReattachConfig{}, closeCh, errors.New("nil reattach config received") 54 } 55 56 return ReattachConfig{ 57 Protocol: string(config.Protocol), 58 Pid: config.Pid, 59 Test: config.Test, 60 Addr: ReattachConfigAddr{ 61 Network: config.Addr.Network(), 62 String: config.Addr.String(), 63 }, 64 }, closeCh, nil 65 } 66 67 // Debug starts a debug server and controls its lifecycle, printing the 68 // information needed for Terraform to connect to the provider to stdout. 69 // os.Interrupt will be captured and used to stop the server. 70 func Debug(ctx context.Context, providerAddr string, opts *ServeOpts) error { 71 ctx, cancel := context.WithCancel(ctx) 72 // Ctrl-C will stop the server 73 sigCh := make(chan os.Signal, 1) 74 signal.Notify(sigCh, os.Interrupt) 75 defer func() { 76 signal.Stop(sigCh) 77 cancel() 78 }() 79 config, closeCh, err := DebugServe(ctx, opts) 80 if err != nil { 81 return fmt.Errorf("Error launching debug server: %v", err) 82 } 83 go func() { 84 select { 85 case <-sigCh: 86 cancel() 87 case <-ctx.Done(): 88 } 89 }() 90 reattachStr, err := json.Marshal(map[string]ReattachConfig{ 91 providerAddr: config, 92 }) 93 if err != nil { 94 return fmt.Errorf("Error building reattach string: %v", err) 95 } 96 97 fmt.Printf("Provider server started; to attach Terraform, set TF_REATTACH_PROVIDERS to the following:\n%s\n", string(reattachStr)) 98 99 // wait for the server to be done 100 <-closeCh 101 return nil 102 }