debug: run interactive shell on error

Launch interactive shell in context of failed action for issues
investigation and debug.

Add options to debos:
--debug-shell -- to start a shell in case of any failure
--shell <path> -- use selected shell instead of default bash

Fixes #30

Signed-off-by: Denis Pynkin <denis.pynkin@collabora.com>
This commit is contained in:
Denis Pynkin
2017-10-13 21:03:59 +03:00
parent d8a6fe12ca
commit ffa64473a5
3 changed files with 56 additions and 9 deletions

View File

@@ -17,6 +17,7 @@ type DebosContext struct {
ImageKernelRoot string // Kernel cmdline root= snippet for the / of the image
RecipeDir string
Architecture string
DebugShell string
Origins map[string]string
}

View File

@@ -13,12 +13,14 @@ import (
"github.com/sjoerdsimons/fakemachine"
)
func bailOnError(err error, a debos.Action, stage string) {
func bailOnError(context debos.DebosContext, err error, a debos.Action, stage string) {
if err == nil {
return
}
log.Fatalf("Action `%s` failed at stage %s, error: %s", a, stage, err)
log.Printf("Action `%s` failed at stage %s, error: %s", a, stage, err)
debos.DebugShell(context)
os.Exit(1)
}
func main() {
@@ -27,6 +29,8 @@ func main() {
ArtifactDir string `long:"artifactdir"`
InternalImage string `long:"internal-image" hidden:"true"`
TemplateVars map[string]string `short:"t" long:"template-var" description:"Template variables"`
DebugShell bool `long:"debug-shell" description:"Fall into interactive shell on error"`
Shell string `short:"s" long:"shell" description:"Redefine interactive shell binary (default: bash)" optionsl:"" default:"/bin/bash"`
}
var exitcode int = 0
@@ -55,6 +59,11 @@ func main() {
return
}
// Set interactive shell binary only if '--debug-shell' options passed
if options.DebugShell {
context.DebugShell = options.Shell
}
file := args[0]
file = debos.CleanPath(file)
@@ -95,7 +104,7 @@ func main() {
for _, a := range r.Actions {
err = a.Verify(&context)
bailOnError(err, a, "Verify")
bailOnError(context, err, a, "Verify")
}
if !fakemachine.InMachine() && fakemachine.Supported() {
@@ -112,9 +121,14 @@ func main() {
m.AddVolume(context.RecipeDir)
args = append(args, file)
if options.DebugShell {
args = append(args, "--debug-shell")
args = append(args, "--shell", fmt.Sprintf("%s", options.Shell))
}
for _, a := range r.Actions {
err = a.PreMachine(&context, m, &args)
bailOnError(err, a, "PreMachine")
bailOnError(context, err, a, "PreMachine")
}
exitcode = m.RunInMachineWithArgs(args)
@@ -125,7 +139,7 @@ func main() {
for _, a := range r.Actions {
err = a.PostMachine(context)
bailOnError(err, a, "Postmachine")
bailOnError(context, err, a, "Postmachine")
}
log.Printf("==== Recipe done ====")
@@ -135,24 +149,25 @@ func main() {
if !fakemachine.InMachine() {
for _, a := range r.Actions {
err = a.PreNoMachine(&context)
bailOnError(err, a, "PreNoMachine")
bailOnError(context, err, a, "PreNoMachine")
}
}
for _, a := range r.Actions {
err = a.Run(&context)
bailOnError(err, a, "Run")
bailOnError(context, err, a, "Run")
}
for _, a := range r.Actions {
err = a.Cleanup(context)
bailOnError(err, a, "Cleanup")
bailOnError(context, err, a, "Cleanup")
}
if !fakemachine.InMachine() {
for _, a := range r.Actions {
err = a.PostMachine(context)
bailOnError(err, a, "PostMachine")
bailOnError(context, err, a, "PostMachine")
}
log.Printf("==== Recipe done ====")
}

31
debug.go Normal file
View File

@@ -0,0 +1,31 @@
package debos
import (
"fmt"
"log"
"os"
)
/*
DebugShell function launches an interactive shell for
debug and problems investigation.
*/
func DebugShell(context DebosContext) {
if len(context.DebugShell) == 0 {
return
}
pa := os.ProcAttr{
Files: []*os.File{os.Stdin, os.Stdout, os.Stderr},
Dir: context.Scratchdir,
}
// Start an interactive shell for debug.
log.Printf(">>> Starting a debug shell")
if proc, err := os.StartProcess(context.DebugShell, []string{}, &pa); err != nil {
fmt.Printf("Failed: %s\n", err)
} else {
proc.Wait()
}
}