mirror of https://github.com/docker/docs.git
Add panic recovery to Create method for drivers
Signed-off-by: Nathan LeClaire <nathan.leclaire@gmail.com>
This commit is contained in:
parent
248596da8a
commit
d80ea22623
|
@ -3,6 +3,8 @@ package rpcdriver
|
||||||
import (
|
import (
|
||||||
"encoding/gob"
|
"encoding/gob"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"runtime/debug"
|
||||||
|
|
||||||
"github.com/docker/machine/libmachine/drivers"
|
"github.com/docker/machine/libmachine/drivers"
|
||||||
"github.com/docker/machine/libmachine/log"
|
"github.com/docker/machine/libmachine/log"
|
||||||
|
@ -11,6 +13,20 @@ import (
|
||||||
"github.com/docker/machine/libmachine/version"
|
"github.com/docker/machine/libmachine/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type Stacker interface {
|
||||||
|
Stack() []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
type StandardStack struct{}
|
||||||
|
|
||||||
|
func (ss *StandardStack) Stack() []byte {
|
||||||
|
return debug.Stack()
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
stdStacker Stacker = &StandardStack{}
|
||||||
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
gob.Register(new(RPCFlags))
|
gob.Register(new(RPCFlags))
|
||||||
gob.Register(new(mcnflag.IntFlag))
|
gob.Register(new(mcnflag.IntFlag))
|
||||||
|
@ -108,8 +124,22 @@ func (r *RPCServerDriver) SetConfigRaw(data []byte, _ *struct{}) error {
|
||||||
return json.Unmarshal(data, &r.ActualDriver)
|
return json.Unmarshal(data, &r.ActualDriver)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *RPCServerDriver) Create(_, _ *struct{}) error {
|
func trapPanic(err *error) {
|
||||||
return r.ActualDriver.Create()
|
if r := recover(); r != nil {
|
||||||
|
*err = fmt.Errorf("Panic in the driver: %s\n%s", r.(error), stdStacker.Stack())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RPCServerDriver) Create(_, _ *struct{}) (err error) {
|
||||||
|
// In an ideal world, plugins wouldn't ever panic. However, panics
|
||||||
|
// have been known to happen and cause issues. Therefore, we recover
|
||||||
|
// and do not crash the RPC server completely in the case of a panic
|
||||||
|
// during create.
|
||||||
|
defer trapPanic(&err)
|
||||||
|
|
||||||
|
err = r.ActualDriver.Create()
|
||||||
|
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *RPCServerDriver) DriverName(_ *struct{}, reply *string) error {
|
func (r *RPCServerDriver) DriverName(_ *struct{}, reply *string) error {
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
package rpcdriver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/docker/machine/drivers/fakedriver"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
type panicDriver struct {
|
||||||
|
*fakedriver.Driver
|
||||||
|
panicErr error
|
||||||
|
returnErr error
|
||||||
|
}
|
||||||
|
|
||||||
|
type FakeStacker struct {
|
||||||
|
trace []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fs *FakeStacker) Stack() []byte {
|
||||||
|
return fs.trace
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *panicDriver) Create() error {
|
||||||
|
if p.panicErr != nil {
|
||||||
|
panic(p.panicErr)
|
||||||
|
}
|
||||||
|
return p.returnErr
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRPCServerDriverCreate(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
description string
|
||||||
|
expectedErr error
|
||||||
|
serverDriver *RPCServerDriver
|
||||||
|
stacker Stacker
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
description: "Happy path",
|
||||||
|
expectedErr: nil,
|
||||||
|
serverDriver: &RPCServerDriver{
|
||||||
|
ActualDriver: &panicDriver{
|
||||||
|
returnErr: nil,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Normal error, no panic",
|
||||||
|
expectedErr: errors.New("API not available"),
|
||||||
|
serverDriver: &RPCServerDriver{
|
||||||
|
ActualDriver: &panicDriver{
|
||||||
|
returnErr: errors.New("API not available"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Panic happened during create",
|
||||||
|
expectedErr: errors.New("Panic in the driver: index out of range\nSTACK TRACE"),
|
||||||
|
serverDriver: &RPCServerDriver{
|
||||||
|
ActualDriver: &panicDriver{
|
||||||
|
panicErr: errors.New("index out of range"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
stacker: &FakeStacker{
|
||||||
|
trace: []byte("STACK TRACE"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
stdStacker = tc.stacker
|
||||||
|
assert.Equal(t, tc.expectedErr, tc.serverDriver.Create(nil, nil))
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue