Skip to content

Commit

Permalink
vm: allow Diagnose to directly return diagnosis
Browse files Browse the repository at this point in the history
Rather than writing the diagnosis to the kernel console, Diagnose can
now directly return the extra debugging info, which will be appended ot
the kernel console log.
  • Loading branch information
prattmic authored and dvyukov committed Dec 21, 2018
1 parent 588075e commit 2fc0110
Show file tree
Hide file tree
Showing 10 changed files with 79 additions and 36 deletions.
4 changes: 2 additions & 2 deletions vm/adb/adb.go
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,6 @@ func (inst *instance) Run(timeout time.Duration, stop <-chan bool, command strin
return vmimpl.Multiplex(adb, merger, tty, timeout, stop, inst.closed, inst.debug)
}

func (inst *instance) Diagnose() bool {
return false
func (inst *instance) Diagnose() ([]byte, bool) {
return nil, false
}
6 changes: 3 additions & 3 deletions vm/gce/gce.go
Original file line number Diff line number Diff line change
Expand Up @@ -366,11 +366,11 @@ func waitForConsoleConnect(merger *vmimpl.OutputMerger) error {
}
}

func (inst *instance) Diagnose() bool {
func (inst *instance) Diagnose() ([]byte, bool) {
if inst.env.OS == "openbsd" {
return vmimpl.DiagnoseOpenBSD(inst.consolew)
return nil, vmimpl.DiagnoseOpenBSD(inst.consolew)
}
return false
return nil, false
}

func (pool *Pool) getSerialPortOutput(name, gceKey string) ([]byte, error) {
Expand Down
4 changes: 2 additions & 2 deletions vm/gvisor/gvisor.go
Original file line number Diff line number Diff line change
Expand Up @@ -327,9 +327,9 @@ func (inst *instance) guestProxy() (*os.File, error) {
return guestSock, nil
}

func (inst *instance) Diagnose() bool {
func (inst *instance) Diagnose() ([]byte, bool) {
osutil.Run(time.Minute, inst.runscCmd("debug", "-signal=12", inst.name))
return true
return nil, true
}

func init() {
Expand Down
4 changes: 2 additions & 2 deletions vm/isolated/isolated.go
Original file line number Diff line number Diff line change
Expand Up @@ -303,8 +303,8 @@ func (inst *instance) Run(timeout time.Duration, stop <-chan bool, command strin
return vmimpl.Multiplex(cmd, merger, dmesg, timeout, stop, inst.closed, inst.debug)
}

func (inst *instance) Diagnose() bool {
return false
func (inst *instance) Diagnose() ([]byte, bool) {
return nil, false
}

func splitTargetPort(addr string) (string, int, error) {
Expand Down
4 changes: 2 additions & 2 deletions vm/kvm/kvm.go
Original file line number Diff line number Diff line change
Expand Up @@ -287,8 +287,8 @@ func (inst *instance) Run(timeout time.Duration, stop <-chan bool, command strin
return outputC, errorC, nil
}

func (inst *instance) Diagnose() bool {
return false
func (inst *instance) Diagnose() ([]byte, bool) {
return nil, false
}

const script = `#! /bin/bash
Expand Down
4 changes: 2 additions & 2 deletions vm/qemu/qemu.go
Original file line number Diff line number Diff line change
Expand Up @@ -512,12 +512,12 @@ func (inst *instance) Run(timeout time.Duration, stop <-chan bool, command strin
return inst.merger.Output, errc, nil
}

func (inst *instance) Diagnose() bool {
func (inst *instance) Diagnose() ([]byte, bool) {
select {
case inst.diagnose <- true:
default:
}
return false
return nil, false
}

// nolint: lll
Expand Down
27 changes: 22 additions & 5 deletions vm/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ func (inst *Instance) Run(timeout time.Duration, stop <-chan bool, command strin
return inst.impl.Run(timeout, stop, command)
}

func (inst *Instance) Diagnose() bool {
func (inst *Instance) Diagnose() ([]byte, bool) {
return inst.impl.Diagnose()
}

Expand Down Expand Up @@ -204,7 +204,12 @@ func (inst *Instance) MonitorExecution(outc <-chan []byte, errc <-chan error,
if time.Since(lastExecuteTime) < noOutputTimeout {
break
}
if inst.Diagnose() {
diag, wait := inst.Diagnose()
if len(diag) > 0 {
mon.output = append(mon.output, "DIAGNOSIS:\n"...)
mon.output = append(mon.output, diag...)
}
if wait {
mon.waitForOutput()
}
rep := &report.Report{
Expand Down Expand Up @@ -232,7 +237,12 @@ type monitor struct {
func (mon *monitor) extractError(defaultError string) *report.Report {
crashed := defaultError != "" || !mon.canExit
if crashed {
mon.inst.Diagnose()
// N.B. we always wait below for other errors.
diag, _ := mon.inst.Diagnose()
if len(diag) > 0 {
mon.output = append(mon.output, "DIAGNOSIS:\n"...)
mon.output = append(mon.output, diag...)
}
}
// Give it some time to finish writing the error message.
mon.waitForOutput()
Expand All @@ -253,8 +263,15 @@ func (mon *monitor) extractError(defaultError string) *report.Report {
}
return rep
}
if !crashed && mon.inst.Diagnose() {
mon.waitForOutput()
if !crashed {
diag, wait := mon.inst.Diagnose()
if len(diag) > 0 {
mon.output = append(mon.output, "DIAGNOSIS:\n"...)
mon.output = append(mon.output, diag...)
}
if wait {
mon.waitForOutput()
}
}
rep := mon.reporter.Parse(mon.output[mon.matchPos:])
if rep == nil {
Expand Down
47 changes: 35 additions & 12 deletions vm/vm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,10 @@ func (pool *testPool) Create(workdir string, index int) (vmimpl.Instance, error)
}

type testInstance struct {
outc chan []byte
errc chan error
diagnoseBug bool
outc chan []byte
errc chan error
diagnoseBug bool
diagnoseNoWait bool
}

func (inst *testInstance) Copy(hostSrc string) (string, error) {
Expand All @@ -49,13 +50,20 @@ func (inst *testInstance) Run(timeout time.Duration, stop <-chan bool, command s
return inst.outc, inst.errc, nil
}

func (inst *testInstance) Diagnose() bool {
func (inst *testInstance) Diagnose() ([]byte, bool) {
var diag []byte
if inst.diagnoseBug {
inst.outc <- []byte("BUG: DIAGNOSE\n")
diag = []byte("BUG: DIAGNOSE\n")
} else {
inst.outc <- []byte("DIAGNOSE\n")
diag = []byte("DIAGNOSE\n")
}
return true

if inst.diagnoseNoWait {
return diag, false
}

inst.outc <- diag
return nil, true
}

func (inst *testInstance) Close() {
Expand All @@ -74,11 +82,12 @@ func init() {
}

type Test struct {
Name string
CanExit bool // if the program is allowed to exit normally
DiagnoseBug bool // Diagnose produces output that is detected as kernel crash
Body func(outc chan []byte, errc chan error)
Report *report.Report
Name string
CanExit bool // if the program is allowed to exit normally
DiagnoseBug bool // Diagnose produces output that is detected as kernel crash
DiagnoseNoWait bool // Diagnose returns output directly rather than to console
Body func(outc chan []byte, errc chan error)
Report *report.Report
}

var tests = []*Test{
Expand Down Expand Up @@ -120,6 +129,19 @@ var tests = []*Test{
),
},
},
{
Name: "diagnose-no-wait",
Body: func(outc chan []byte, errc chan error) {
errc <- nil
},
DiagnoseNoWait: true,
Report: &report.Report{
Title: lostConnectionCrash,
Output: []byte(
"DIAGNOSIS:\nDIAGNOSE\n",
),
},
},
{
Name: "kernel-crashes",
Body: func(outc chan []byte, errc chan error) {
Expand Down Expand Up @@ -280,6 +302,7 @@ func testMonitorExecution(t *testing.T, test *Test) {
}
testInst := inst.impl.(*testInstance)
testInst.diagnoseBug = test.DiagnoseBug
testInst.diagnoseNoWait = test.DiagnoseNoWait
done := make(chan bool)
go func() {
test.Body(testInst.outc, testInst.errc)
Expand Down
11 changes: 7 additions & 4 deletions vm/vmimpl/vmimpl.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,13 @@ type Instance interface {
// Command is terminated after timeout. Send on the stop chan can be used to terminate it earlier.
Run(timeout time.Duration, stop <-chan bool, command string) (outc <-chan []byte, errc <-chan error, err error)

// Diagnose forces VM to dump additional debugging info
// (e.g. sending some sys-rq's or SIGABORT'ing a Go program).
// Returns true if it did anything.
Diagnose() bool
// Diagnose retrieves additional debugging info from the VM (e.g. by
// sending some sys-rq's or SIGABORT'ing a Go program).
//
// Optionally returns (some or all) of the info directly. If wait ==
// true, the caller must wait for the VM to output info directly to its
// log.
Diagnose() (diagnosis []byte, wait bool)

// Close stops and destroys the VM.
Close()
Expand Down
4 changes: 2 additions & 2 deletions vm/vmm/vmm.go
Original file line number Diff line number Diff line change
Expand Up @@ -310,8 +310,8 @@ func (inst *instance) Run(timeout time.Duration, stop <-chan bool, command strin
return inst.merger.Output, errc, nil
}

func (inst *instance) Diagnose() bool {
return vmimpl.DiagnoseOpenBSD(inst.consolew)
func (inst *instance) Diagnose() ([]byte, bool) {
return nil, vmimpl.DiagnoseOpenBSD(inst.consolew)
}

// Run the given vmctl(8) command and wait for it to finish.
Expand Down

0 comments on commit 2fc0110

Please sign in to comment.