fix panic with deadlines. update panicwrap dep

This commit is contained in:
Matthew Hooker 2017-06-15 01:15:32 -07:00
parent 7382382727
commit 35332e4498
No known key found for this signature in database
GPG Key ID: 7B5F933D9CE8C6A1
5 changed files with 71 additions and 10 deletions

View File

@ -85,6 +85,7 @@ func realMain() int {
wrapConfig.Handler = panicHandler(logTempFile) wrapConfig.Handler = panicHandler(logTempFile)
wrapConfig.Writer = io.MultiWriter(logTempFile, logWriter) wrapConfig.Writer = io.MultiWriter(logTempFile, logWriter)
wrapConfig.Stdout = outW wrapConfig.Stdout = outW
wrapConfig.DetectDuration = 500 * time.Millisecond
exitStatus, err := panicwrap.Wrap(&wrapConfig) exitStatus, err := panicwrap.Wrap(&wrapConfig)
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "Couldn't start Packer: %s", err) fmt.Fprintf(os.Stderr, "Couldn't start Packer: %s", err)

View File

@ -1,6 +1,7 @@
package packer package packer
import ( import (
"context"
"fmt" "fmt"
"log" "log"
"os" "os"
@ -79,7 +80,11 @@ func (c *CheckpointTelemetry) ReportPanic(m string) error {
panicParams := c.baseParams(TelemetryPanicVersion) panicParams := c.baseParams(TelemetryPanicVersion)
panicParams.Payload = m panicParams.Payload = m
panicParams.EndTime = time.Now().UTC() 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 { 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 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 { type TelemetrySpan struct {

View File

@ -4,6 +4,7 @@ package checkpoint
import ( import (
"bytes" "bytes"
"context"
"crypto/rand" "crypto/rand"
"encoding/binary" "encoding/binary"
"encoding/json" "encoding/json"
@ -64,7 +65,7 @@ func (i *ReportParams) signature() string {
return signature return signature
} }
func Report(r *ReportParams) error { func Report(ctx context.Context, r *ReportParams) error {
if disabled := os.Getenv("CHECKPOINT_DISABLE"); disabled != "" { if disabled := os.Getenv("CHECKPOINT_DISABLE"); disabled != "" {
return nil return nil
} }
@ -117,7 +118,7 @@ func Report(r *ReportParams) error {
req.Header.Add("User-Agent", "HashiCorp/go-checkpoint") req.Header.Add("User-Agent", "HashiCorp/go-checkpoint")
client := cleanhttp.DefaultClient() client := cleanhttp.DefaultClient()
resp, err := client.Do(req) resp, err := client.Do(req.WithContext(ctx))
if err != nil { if err != nil {
return err return err
} }

View File

@ -12,13 +12,16 @@ package panicwrap
import ( import (
"bytes" "bytes"
"errors" "errors"
"github.com/kardianos/osext"
"io" "io"
"os" "os"
"os/exec" "os/exec"
"os/signal" "os/signal"
"runtime"
"sync/atomic"
"syscall" "syscall"
"time" "time"
"github.com/kardianos/osext"
) )
const ( const (
@ -61,6 +64,17 @@ type WrapConfig struct {
// The writer to send stdout to. If this is nil, then it defaults to // The writer to send stdout to. If this is nil, then it defaults to
// os.Stdout. // os.Stdout.
Stdout io.Writer 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 // 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.Stdin = os.Stdin
cmd.Stdout = stdout_w cmd.Stdout = stdout_w
cmd.Stderr = stderr_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 { if err := cmd.Start(); err != nil {
return 1, err return 1, err
} }
@ -152,13 +173,23 @@ func Wrap(c *WrapConfig) (int, error) {
// Listen to signals and capture them forever. We allow the child // Listen to signals and capture them forever. We allow the child
// process to handle them in some way. // process to handle them in some way.
sigCh := make(chan os.Signal) 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() { go func() {
defer signal.Stop(sigCh) defer signal.Stop(sigCh)
defer signal.Stop(fwdSigCh)
for { for {
select { select {
case <-doneCh: case <-doneCh:
return return
case s := <-fwdSigCh:
if cmd.Process != nil {
cmd.Process.Signal(s)
}
case <-sigCh: 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 // Wrapped is very cheap and can be used early to short-circuit some pre-wrap
// logic your application may have. // 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 { func Wrapped(c *WrapConfig) bool {
if c == nil {
return wrapCache.Load().(bool)
}
if c.CookieKey == "" { if c.CookieKey == "" {
c.CookieKey = DEFAULT_COOKIE_KEY 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 // 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 // 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, // trackPanic monitors the given reader for a panic. If a panic is detected,

7
vendor/vendor.json vendored
View File

@ -546,7 +546,7 @@
"revision": "7554cd9344cec97297fa6649b055a8c98c2a1e55" "revision": "7554cd9344cec97297fa6649b055a8c98c2a1e55"
}, },
{ {
"checksumSHA1": "rPdTLJsefFK1hgWuVXcM9wmnSMI=", "checksumSHA1": "kBuCrFoNYcM0PcdbrOJQwec3Heg=",
"path": "github.com/hashicorp/go-checkpoint", "path": "github.com/hashicorp/go-checkpoint",
"revision": "194925eac2c1f69fcac1693d3f02f1337c341763", "revision": "194925eac2c1f69fcac1693d3f02f1337c341763",
"revisionTime": "2017-06-15T06:56:40Z" "revisionTime": "2017-06-15T06:56:40Z"
@ -719,9 +719,10 @@
"revisionTime": "2017-03-16T18:53:39Z" "revisionTime": "2017-03-16T18:53:39Z"
}, },
{ {
"checksumSHA1": "VBo7ciCNRr7wNVFmBTW8sm4PQ14=", "checksumSHA1": "m2L8ohfZiFRsMW3iynaH/TWgnSY=",
"path": "github.com/mitchellh/panicwrap", "path": "github.com/mitchellh/panicwrap",
"revision": "a1e50bc201f387747a45ffff020f1af2d8759e88" "revision": "fce601fe55579125e1b3cb0b992287e7290f7b83",
"revisionTime": "2017-01-06T18:23:40Z"
}, },
{ {
"checksumSHA1": "h+ODp7a8Vj8XMUsORLbhtQMWOO4=", "checksumSHA1": "h+ODp7a8Vj8XMUsORLbhtQMWOO4=",