oci: use json formatted errors from the runtime

request json formatted error messages from the OCI runtime so that we
can nicely print them.

Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
This commit is contained in:
Giuseppe Scrivano 2019-06-12 22:35:25 +02:00
parent 77d1cf0a32
commit 6e4ce54d33
No known key found for this signature in database
GPG Key ID: E4730F97F60286ED
3 changed files with 27 additions and 2 deletions

View File

@ -96,4 +96,7 @@ var (
// ErrOSNotSupported indicates the function is not available on the particular // ErrOSNotSupported indicates the function is not available on the particular
// OS. // OS.
ErrOSNotSupported = errors.New("No support for this OS yet") ErrOSNotSupported = errors.New("No support for this OS yet")
// ErrOCIRuntime indicates an error from the OCI runtime
ErrOCIRuntime = errors.New("OCI runtime error")
) )

View File

@ -66,6 +66,14 @@ type syncInfo struct {
Message string `json:"message,omitempty"` Message string `json:"message,omitempty"`
} }
// ociError is used to parse the OCI runtime JSON log. It is not part of the
// OCI runtime specifications, it follows what runc does
type ociError struct {
Level string `json:"level,omitempty"`
Time string `json:"time,omitempty"`
Msg string `json:"msg,omitempty"`
}
// Make a new OCI runtime with provided options // Make a new OCI runtime with provided options
func newOCIRuntime(oruntime OCIRuntimePath, conmonPath string, conmonEnv []string, cgroupManager string, tmpDir string, logSizeMax int64, noPivotRoot bool, reservePorts bool) (*OCIRuntime, error) { func newOCIRuntime(oruntime OCIRuntimePath, conmonPath string, conmonEnv []string, cgroupManager string, tmpDir string, logSizeMax int64, noPivotRoot bool, reservePorts bool) (*OCIRuntime, error) {
runtime := new(OCIRuntime) runtime := new(OCIRuntime)

View File

@ -6,6 +6,7 @@ import (
"bufio" "bufio"
"bytes" "bytes"
"fmt" "fmt"
"io/ioutil"
"os" "os"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
@ -208,6 +209,9 @@ func (r *OCIRuntime) createOCIContainer(ctr *Container, cgroupParent string, res
defer parentPipe.Close() defer parentPipe.Close()
defer parentStartPipe.Close() defer parentStartPipe.Close()
ociLog := filepath.Join(ctr.state.RunDir, "oci-log")
logLevel := logrus.GetLevel()
args := []string{} args := []string{}
if r.cgroupManager == SystemdCgroupsManager { if r.cgroupManager == SystemdCgroupsManager {
args = append(args, "-s") args = append(args, "-s")
@ -219,6 +223,9 @@ func (r *OCIRuntime) createOCIContainer(ctr *Container, cgroupParent string, res
args = append(args, "-b", ctr.bundlePath()) args = append(args, "-b", ctr.bundlePath())
args = append(args, "-p", filepath.Join(ctr.state.RunDir, "pidfile")) args = append(args, "-p", filepath.Join(ctr.state.RunDir, "pidfile"))
args = append(args, "--exit-dir", r.exitsDir) args = append(args, "--exit-dir", r.exitsDir)
if logLevel != logrus.DebugLevel {
args = append(args, "--runtime-arg", "--log-format=json", "--runtime-arg", "--log", fmt.Sprintf("--runtime-arg=%s", ociLog))
}
if ctr.config.ConmonPidFile != "" { if ctr.config.ConmonPidFile != "" {
args = append(args, "--conmon-pidfile", ctr.config.ConmonPidFile) args = append(args, "--conmon-pidfile", ctr.config.ConmonPidFile)
} }
@ -248,7 +255,6 @@ func (r *OCIRuntime) createOCIContainer(ctr *Container, cgroupParent string, res
args = append(args, "--no-pivot") args = append(args, "--no-pivot")
} }
logLevel := logrus.GetLevel()
args = append(args, "--log-level", logLevel.String()) args = append(args, "--log-level", logLevel.String())
if logLevel == logrus.DebugLevel { if logLevel == logrus.DebugLevel {
@ -417,8 +423,16 @@ func (r *OCIRuntime) createOCIContainer(ctr *Container, cgroupParent string, res
} }
logrus.Debugf("Received container pid: %d", ss.si.Pid) logrus.Debugf("Received container pid: %d", ss.si.Pid)
if ss.si.Pid == -1 { if ss.si.Pid == -1 {
data, err := ioutil.ReadFile(ociLog)
if err == nil {
var ociErr ociError
if err := json.Unmarshal(data, &ociErr); err == nil {
return errors.Wrapf(ErrOCIRuntime, "%s", strings.Trim(ociErr.Msg, "\n"))
}
}
// If we failed to parse the JSON errors, then print the output as it is
if ss.si.Message != "" { if ss.si.Message != "" {
return errors.Wrapf(ErrInternal, "container create failed: %s", ss.si.Message) return errors.Wrapf(ErrOCIRuntime, "%s", ss.si.Message)
} }
return errors.Wrapf(ErrInternal, "container create failed") return errors.Wrapf(ErrInternal, "container create failed")
} }