Skip to content

Commit

Permalink
agent: support debug console
Browse files Browse the repository at this point in the history
Start a debug console if the `agent.debug_console` option is part of the kernel
command line and a shell (bash or sh) is installed in the rootfs.
The debug console is useful when the developer wants to debug the agent process
or any other processes (even containers). The current way to do this is by
modifying a systemd target + creating a new system unit, the problem with this
approach is that it's not user-friendly and we depend on systemd, since it must
be installed in the rootfs.

fixes kata-containers#546

Signed-off-by: Julio Montes <julio.montes@intel.com>
  • Loading branch information
Julio Montes committed May 3, 2019
1 parent 629f90f commit 0af7173
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 0 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* [Debug mode](#debug-mode)
* [Developer mode](#developer-mode)
* [Enable trace support](#enable-trace-support)
* [Enable debug console](#enable-debug-console)

This project implements an agent called `kata-agent` that runs inside a virtual machine (VM).

Expand All @@ -27,3 +28,10 @@ enables [debug mode](#debug-mode).
## Enable trace support

See [the tracing guide](TRACING.md).

## Enable debug console

Add `agent.debug_console` to the guest kernel command line to
allow the agent process to start a debug console. Debug console is only available if `bash`
or `sh` is installed in the rootfs or initrd image. Developers can [connect to the virtual
machine using the debug console](https://github.com/kata-containers/documentation/blob/master/Developer-Guide.md#connect-to-the-virtual-machine-using-the-debug-console)
63 changes: 63 additions & 0 deletions agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ import (
const (
procCgroups = "/proc/cgroups"
meminfo = "/proc/meminfo"

bashPath = "/bin/bash"
shPath = "/bin/sh"
debugConsolePath = "/dev/console"
)

var (
Expand Down Expand Up @@ -156,6 +160,9 @@ var collatedTrace = false
// if true, coredump when an internal error occurs or a fatal signal is received
var crashOnError = false

// if true, a shell (bash or sh) is started only if it's available in the rootfs.
var debugConsole = false

// commType is used to denote the communication channel type used.
type commType int

Expand Down Expand Up @@ -911,6 +918,8 @@ func (s *sandbox) initLogger() error {

agentLog.Logger.SetLevel(config.logLevel)

agentLog = agentLog.WithField("debug_console", debugConsole)

return announce()
}

Expand Down Expand Up @@ -1196,6 +1205,56 @@ func cgroupsMount() error {
return ioutil.WriteFile(cgroupMemoryUseHierarchyPath, []byte{'1'}, cgroupMemoryUseHierarchyMode)
}

func setupDebugConsole() error {
if !debugConsole {
return nil
}

var shellPath string
for _, s := range []string{bashPath, shPath} {
var err error
if _, err = os.Stat(s); err == nil {
shellPath = s
break
}
agentLog.WithError(err).WithField("shell", s).Warn("Shell not found")
}

if shellPath == "" {
return errors.New("Shell not found")
}

cmd := exec.Command(shellPath)
cmd.Env = os.Environ()
f, err := os.OpenFile(debugConsolePath, os.O_RDWR, 0600)
if err != nil {
return err
}

cmd.Stdin = f
cmd.Stdout = f
cmd.Stderr = f

cmd.SysProcAttr = &syscall.SysProcAttr{
// Create Session
Setsid: true,
// Set Controlling terminal to Ctty
Setctty: true,
Ctty: int(f.Fd()),
}

go func() {
for {
dcmd := *cmd
if err := dcmd.Run(); err != nil {
agentLog.WithError(err).Warn("failed to start debug console")
}
}
}()

return nil
}

// initAgentAsInit will do the initializations such as setting up the rootfs
// when this agent has been run as the init process.
func initAgentAsInit() error {
Expand Down Expand Up @@ -1271,6 +1330,10 @@ func realMain() error {
return fmt.Errorf("failed to setup logger: %v", err)
}

if err := setupDebugConsole(); err != nil {
agentLog.WithError(err).Error("failed to setup debug console")
}

rootSpan, rootContext, err = setupTracing(agentName)
if err != nil {
return fmt.Errorf("failed to setup tracing: %v", err)
Expand Down
6 changes: 6 additions & 0 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const (
devModeFlag = optionPrefix + "devmode"
traceModeFlag = optionPrefix + "trace"
useVsockFlag = optionPrefix + "use_vsock"
debugConsoleFlag = optionPrefix + "debug_console"
kernelCmdlineFile = "/proc/cmdline"
traceModeStatic = "static"
traceModeDynamic = "dynamic"
Expand Down Expand Up @@ -79,6 +80,11 @@ func (c *agentConfig) parseCmdlineOption(option string) error {
return nil
}

if option == debugConsoleFlag {
debugConsole = true
return nil
}

if option == traceModeFlag {
enableTracing(traceModeStatic, defaultTraceType)
return nil
Expand Down

0 comments on commit 0af7173

Please sign in to comment.