From 6e4ce54d33df0c43392fd247d42106802ca556df Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Wed, 12 Jun 2019 22:35:25 +0200 Subject: 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 --- libpod/errors.go | 3 +++ libpod/oci.go | 8 ++++++++ libpod/oci_linux.go | 18 ++++++++++++++++-- 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/libpod/errors.go b/libpod/errors.go index dd82d0796..cca0935ec 100644 --- a/libpod/errors.go +++ b/libpod/errors.go @@ -96,4 +96,7 @@ var ( // ErrOSNotSupported indicates the function is not available on the particular // OS. ErrOSNotSupported = errors.New("No support for this OS yet") + + // ErrOCIRuntime indicates an error from the OCI runtime + ErrOCIRuntime = errors.New("OCI runtime error") ) diff --git a/libpod/oci.go b/libpod/oci.go index 7138108c5..0a730b799 100644 --- a/libpod/oci.go +++ b/libpod/oci.go @@ -66,6 +66,14 @@ type syncInfo struct { 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 func newOCIRuntime(oruntime OCIRuntimePath, conmonPath string, conmonEnv []string, cgroupManager string, tmpDir string, logSizeMax int64, noPivotRoot bool, reservePorts bool) (*OCIRuntime, error) { runtime := new(OCIRuntime) diff --git a/libpod/oci_linux.go b/libpod/oci_linux.go index 7c1c18052..b9820ce9f 100644 --- a/libpod/oci_linux.go +++ b/libpod/oci_linux.go @@ -6,6 +6,7 @@ import ( "bufio" "bytes" "fmt" + "io/ioutil" "os" "os/exec" "path/filepath" @@ -208,6 +209,9 @@ func (r *OCIRuntime) createOCIContainer(ctr *Container, cgroupParent string, res defer parentPipe.Close() defer parentStartPipe.Close() + ociLog := filepath.Join(ctr.state.RunDir, "oci-log") + logLevel := logrus.GetLevel() + args := []string{} if r.cgroupManager == SystemdCgroupsManager { 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, "-p", filepath.Join(ctr.state.RunDir, "pidfile")) 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 != "" { 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") } - logLevel := logrus.GetLevel() args = append(args, "--log-level", logLevel.String()) 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) 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 != "" { - 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") } -- cgit v1.2.3-54-g00ecf