diff --git a/main.go b/main.go index 43ae94f4a..47dc7e506 100644 --- a/main.go +++ b/main.go @@ -85,6 +85,7 @@ func realMain() int { wrapConfig.Handler = panicHandler(logTempFile) wrapConfig.Writer = io.MultiWriter(logTempFile, logWriter) wrapConfig.Stdout = outW + wrapConfig.DetectDuration = 500 * time.Millisecond exitStatus, err := panicwrap.Wrap(&wrapConfig) if err != nil { fmt.Fprintf(os.Stderr, "Couldn't start Packer: %s", err) diff --git a/packer/telemetry.go b/packer/telemetry.go index 9ff22ad22..ef7a4852b 100644 --- a/packer/telemetry.go +++ b/packer/telemetry.go @@ -1,6 +1,7 @@ package packer import ( + "context" "fmt" "log" "os" @@ -79,7 +80,11 @@ func (c *CheckpointTelemetry) ReportPanic(m string) error { panicParams := c.baseParams(TelemetryPanicVersion) panicParams.Payload = m panicParams.EndTime = time.Now().UTC() - return checkpoint.Report(panicParams) + + ctx, cancel := context.WithTimeout(context.Background(), 4500*time.Millisecond) + defer cancel() + + return checkpoint.Report(ctx, panicParams) } func (c *CheckpointTelemetry) AddSpan(name, pluginType string) *TelemetrySpan { @@ -112,7 +117,10 @@ func (c *CheckpointTelemetry) Finalize(command string, errCode int, err error) e } params.Payload = extra - return checkpoint.Report(params) + ctx, cancel := context.WithTimeout(context.Background(), 450*time.Millisecond) + defer cancel() + + return checkpoint.Report(ctx, params) } type TelemetrySpan struct { diff --git a/vendor/github.com/hashicorp/go-checkpoint/checkpoint.go b/vendor/github.com/hashicorp/go-checkpoint/checkpoint.go index 8dff68f80..2fc442d1f 100644 --- a/vendor/github.com/hashicorp/go-checkpoint/checkpoint.go +++ b/vendor/github.com/hashicorp/go-checkpoint/checkpoint.go @@ -4,6 +4,7 @@ package checkpoint import ( "bytes" + "context" "crypto/rand" "encoding/binary" "encoding/json" @@ -64,7 +65,7 @@ func (i *ReportParams) signature() string { return signature } -func Report(r *ReportParams) error { +func Report(ctx context.Context, r *ReportParams) error { if disabled := os.Getenv("CHECKPOINT_DISABLE"); disabled != "" { return nil } @@ -117,7 +118,7 @@ func Report(r *ReportParams) error { req.Header.Add("User-Agent", "HashiCorp/go-checkpoint") client := cleanhttp.DefaultClient() - resp, err := client.Do(req) + resp, err := client.Do(req.WithContext(ctx)) if err != nil { return err } diff --git a/vendor/github.com/mitchellh/panicwrap/panicwrap.go b/vendor/github.com/mitchellh/panicwrap/panicwrap.go index 11eafe712..028d69bfe 100644 --- a/vendor/github.com/mitchellh/panicwrap/panicwrap.go +++ b/vendor/github.com/mitchellh/panicwrap/panicwrap.go @@ -12,13 +12,16 @@ package panicwrap import ( "bytes" "errors" - "github.com/kardianos/osext" "io" "os" "os/exec" "os/signal" + "runtime" + "sync/atomic" "syscall" "time" + + "github.com/kardianos/osext" ) const ( @@ -61,6 +64,17 @@ type WrapConfig struct { // The writer to send stdout to. If this is nil, then it defaults to // os.Stdout. Stdout io.Writer + + // Catch and igore these signals in the parent process, let the child + // handle them gracefully. + IgnoreSignals []os.Signal + + // Catch these signals in the parent process and manually forward + // them to the child process. Some signals such as SIGINT are usually + // sent to the entire process group so setting it isn't necessary. Other + // signals like SIGTERM are only sent to the parent process and need + // to be forwarded. This defaults to empty. + ForwardSignals []os.Signal } // BasicWrap calls Wrap with the given handler function, using defaults @@ -145,6 +159,13 @@ func Wrap(c *WrapConfig) (int, error) { cmd.Stdin = os.Stdin cmd.Stdout = stdout_w cmd.Stderr = stderr_w + + // Windows doesn't support this, but on other platforms pass in + // the original file descriptors so they can be used. + if runtime.GOOS != "windows" { + cmd.ExtraFiles = []*os.File{os.Stdin, os.Stdout, os.Stderr} + } + if err := cmd.Start(); err != nil { return 1, err } @@ -152,13 +173,23 @@ func Wrap(c *WrapConfig) (int, error) { // Listen to signals and capture them forever. We allow the child // process to handle them in some way. sigCh := make(chan os.Signal) - signal.Notify(sigCh, os.Interrupt) + fwdSigCh := make(chan os.Signal) + if len(c.IgnoreSignals) == 0 { + c.IgnoreSignals = []os.Signal{os.Interrupt} + } + signal.Notify(sigCh, c.IgnoreSignals...) + signal.Notify(fwdSigCh, c.ForwardSignals...) go func() { defer signal.Stop(sigCh) + defer signal.Stop(fwdSigCh) for { select { case <-doneCh: return + case s := <-fwdSigCh: + if cmd.Process != nil { + cmd.Process.Signal(s) + } case <-sigCh: } } @@ -200,7 +231,17 @@ func Wrap(c *WrapConfig) (int, error) { // // Wrapped is very cheap and can be used early to short-circuit some pre-wrap // logic your application may have. +// +// If the given configuration is nil, then this will return a cached +// value of Wrapped. This is useful because Wrapped is usually called early +// to verify a process hasn't been wrapped before wrapping. After this, +// the value of Wrapped hardly changes and is process-global, so other +// libraries can check with Wrapped(nil). func Wrapped(c *WrapConfig) bool { + if c == nil { + return wrapCache.Load().(bool) + } + if c.CookieKey == "" { c.CookieKey = DEFAULT_COOKIE_KEY } @@ -211,7 +252,16 @@ func Wrapped(c *WrapConfig) bool { // If the cookie key/value match our environment, then we are the // child, so just exit now and tell the caller that we're the child - return os.Getenv(c.CookieKey) == c.CookieValue + result := os.Getenv(c.CookieKey) == c.CookieValue + wrapCache.Store(result) + return result +} + +// wrapCache is the cached value for Wrapped when called with nil +var wrapCache atomic.Value + +func init() { + wrapCache.Store(false) } // trackPanic monitors the given reader for a panic. If a panic is detected, diff --git a/vendor/vendor.json b/vendor/vendor.json index dce822a05..05ab00d06 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -546,7 +546,7 @@ "revision": "7554cd9344cec97297fa6649b055a8c98c2a1e55" }, { - "checksumSHA1": "rPdTLJsefFK1hgWuVXcM9wmnSMI=", + "checksumSHA1": "kBuCrFoNYcM0PcdbrOJQwec3Heg=", "path": "github.com/hashicorp/go-checkpoint", "revision": "194925eac2c1f69fcac1693d3f02f1337c341763", "revisionTime": "2017-06-15T06:56:40Z" @@ -719,9 +719,10 @@ "revisionTime": "2017-03-16T18:53:39Z" }, { - "checksumSHA1": "VBo7ciCNRr7wNVFmBTW8sm4PQ14=", + "checksumSHA1": "m2L8ohfZiFRsMW3iynaH/TWgnSY=", "path": "github.com/mitchellh/panicwrap", - "revision": "a1e50bc201f387747a45ffff020f1af2d8759e88" + "revision": "fce601fe55579125e1b3cb0b992287e7290f7b83", + "revisionTime": "2017-01-06T18:23:40Z" }, { "checksumSHA1": "h+ODp7a8Vj8XMUsORLbhtQMWOO4=",