mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-04-29 12:14:48 +00:00
runtime: Collect QEMU's stderr
LaunchQemu now connects a pipe to QEMU's stderr and makes it usable by callers through a Go io.ReadCloser object. As explained in [0], all messages should be read from the pipe before calling cmd.Wait : introduce a LogAndWait helper to handle that. Fixes #5780 Signed-off-by: Greg Kurz <groug@kaod.org>
This commit is contained in:
parent
a5319c6be6
commit
39fe4a4b6f
@ -32,7 +32,7 @@ func Example() {
|
|||||||
// flag.
|
// flag.
|
||||||
// It will set up a unix domain socket called /tmp/qmp-socket that we
|
// It will set up a unix domain socket called /tmp/qmp-socket that we
|
||||||
// can use to manage the instance.
|
// can use to manage the instance.
|
||||||
proc, err := qemu.LaunchCustomQemu(context.Background(), "", params, nil, nil, nil)
|
proc, _, err := qemu.LaunchCustomQemu(context.Background(), "", params, nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ package qemu
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
@ -2985,7 +2986,7 @@ func (config *Config) appendFwCfg(logger QMPLog) {
|
|||||||
// The Config parameter contains a set of qemu parameters and settings.
|
// The Config parameter contains a set of qemu parameters and settings.
|
||||||
//
|
//
|
||||||
// See LaunchCustomQemu for more information.
|
// See LaunchCustomQemu for more information.
|
||||||
func LaunchQemu(config Config, logger QMPLog) (*exec.Cmd, error) {
|
func LaunchQemu(config Config, logger QMPLog) (*exec.Cmd, io.ReadCloser, error) {
|
||||||
config.appendName()
|
config.appendName()
|
||||||
config.appendUUID()
|
config.appendUUID()
|
||||||
config.appendMachine()
|
config.appendMachine()
|
||||||
@ -3008,7 +3009,7 @@ func LaunchQemu(config Config, logger QMPLog) (*exec.Cmd, error) {
|
|||||||
config.appendSeccompSandbox()
|
config.appendSeccompSandbox()
|
||||||
|
|
||||||
if err := config.appendCPUs(); err != nil {
|
if err := config.appendCPUs(); err != nil {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := config.Ctx
|
ctx := config.Ctx
|
||||||
@ -3039,11 +3040,12 @@ func LaunchQemu(config Config, logger QMPLog) (*exec.Cmd, error) {
|
|||||||
//
|
//
|
||||||
// This function writes its log output via logger parameter.
|
// This function writes its log output via logger parameter.
|
||||||
//
|
//
|
||||||
// The function returns cmd, nil where cmd is a Go exec.Cmd object
|
// The function returns cmd, reader, nil where cmd is a Go exec.Cmd object
|
||||||
// representing the QEMU process if launched successfully. Otherwise
|
// representing the QEMU process and reader a Go io.ReadCloser object
|
||||||
// nil, err where err is a Go error object is returned.
|
// connected to QEMU's stderr, if launched successfully. Otherwise
|
||||||
|
// nil, nil, err where err is a Go error object is returned.
|
||||||
func LaunchCustomQemu(ctx context.Context, path string, params []string, fds []*os.File,
|
func LaunchCustomQemu(ctx context.Context, path string, params []string, fds []*os.File,
|
||||||
attr *syscall.SysProcAttr, logger QMPLog) (*exec.Cmd, error) {
|
attr *syscall.SysProcAttr, logger QMPLog) (*exec.Cmd, io.ReadCloser, error) {
|
||||||
if logger == nil {
|
if logger == nil {
|
||||||
logger = qmpNullLogger{}
|
logger = qmpNullLogger{}
|
||||||
}
|
}
|
||||||
@ -3061,12 +3063,17 @@ func LaunchCustomQemu(ctx context.Context, path string, params []string, fds []*
|
|||||||
|
|
||||||
cmd.SysProcAttr = attr
|
cmd.SysProcAttr = attr
|
||||||
|
|
||||||
|
reader, err := cmd.StderrPipe()
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("Unable to connect stderr to a pipe")
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
logger.Infof("launching %s with: %v", path, params)
|
logger.Infof("launching %s with: %v", path, params)
|
||||||
|
|
||||||
err := cmd.Start()
|
err = cmd.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Errorf("Unable to launch %s: %v", path, err)
|
logger.Errorf("Unable to launch %s: %v", path, err)
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
return cmd, nil
|
return cmd, reader, nil
|
||||||
}
|
}
|
||||||
|
@ -13,11 +13,14 @@ import (
|
|||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"math"
|
"math"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
|
"os/exec"
|
||||||
"os/user"
|
"os/user"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
@ -865,6 +868,24 @@ func (q *qemu) setupEarlyQmpConnection() (net.Conn, error) {
|
|||||||
return conn, nil
|
return conn, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (q *qemu) LogAndWait(qemuCmd *exec.Cmd, reader io.ReadCloser) {
|
||||||
|
pid := qemuCmd.Process.Pid
|
||||||
|
q.Logger().Infof("Start logging QEMU (qemuPid=%d)", pid)
|
||||||
|
scanner := bufio.NewScanner(reader)
|
||||||
|
warnRE := regexp.MustCompile("(^[^:]+: )warning: ")
|
||||||
|
for scanner.Scan() {
|
||||||
|
text := scanner.Text()
|
||||||
|
if warnRE.MatchString(text) {
|
||||||
|
text = warnRE.ReplaceAllString(text, "$1")
|
||||||
|
q.Logger().WithField("qemuPid", pid).Warning(text)
|
||||||
|
} else {
|
||||||
|
q.Logger().WithField("qemuPid", pid).Error(text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
q.Logger().Infof("Stop logging QEMU (qemuPid=%d)", pid)
|
||||||
|
qemuCmd.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
// StartVM will start the Sandbox's VM.
|
// StartVM will start the Sandbox's VM.
|
||||||
func (q *qemu) StartVM(ctx context.Context, timeout int) error {
|
func (q *qemu) StartVM(ctx context.Context, timeout int) error {
|
||||||
span, ctx := katatrace.Trace(ctx, q.Logger(), "StartVM", qemuTracingTags, map[string]string{"sandbox_id": q.id})
|
span, ctx := katatrace.Trace(ctx, q.Logger(), "StartVM", qemuTracingTags, map[string]string{"sandbox_id": q.id})
|
||||||
@ -941,7 +962,7 @@ func (q *qemu) StartVM(ctx context.Context, timeout int) error {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
qemuCmd, err := govmmQemu.LaunchQemu(q.qemuConfig, newQMPLogger())
|
qemuCmd, reader, err := govmmQemu.LaunchQemu(q.qemuConfig, newQMPLogger())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
q.Logger().WithError(err).Error("failed to launch qemu")
|
q.Logger().WithError(err).Error("failed to launch qemu")
|
||||||
return fmt.Errorf("failed to launch qemu: %s", err)
|
return fmt.Errorf("failed to launch qemu: %s", err)
|
||||||
@ -952,10 +973,9 @@ func (q *qemu) StartVM(ctx context.Context, timeout int) error {
|
|||||||
// actually started.
|
// actually started.
|
||||||
qemuCmd.Wait()
|
qemuCmd.Wait()
|
||||||
} else {
|
} else {
|
||||||
// Ensure the QEMU process is reaped after termination
|
// Log QEMU errors and ensure the QEMU process is reaped after
|
||||||
go func() {
|
// termination.
|
||||||
qemuCmd.Wait()
|
go q.LogAndWait(qemuCmd, reader)
|
||||||
}()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err = q.waitVM(ctx, qmpConn, timeout)
|
err = q.waitVM(ctx, qmpConn, timeout)
|
||||||
|
Loading…
Reference in New Issue
Block a user