Skip to content

Commit a7a402a

Browse files
authored
Merge pull request #4928 from kolyshkin/better-init-errors
Better errors from `runc init`
2 parents 21ad0e4 + f944cce commit a7a402a

File tree

2 files changed

+40
-16
lines changed

2 files changed

+40
-16
lines changed

libcontainer/container_linux.go

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -338,8 +338,6 @@ func (c *Container) start(process *Process) (retErr error) {
338338
// We do not need the cloned binaries once the process is spawned.
339339
defer process.closeClonedExes()
340340

341-
logsDone := parent.forwardChildLogs()
342-
343341
// Before starting "runc init", mark all non-stdio open files as O_CLOEXEC
344342
// to make sure we don't leak any files into "runc init". Any files to be
345343
// passed to "runc init" through ExtraFiles will get dup2'd by the Go
@@ -349,21 +347,28 @@ func (c *Container) start(process *Process) (retErr error) {
349347
if err := utils.CloseExecFrom(3); err != nil {
350348
return fmt.Errorf("unable to mark non-stdio fds as cloexec: %w", err)
351349
}
352-
if err := parent.start(); err != nil {
353-
return fmt.Errorf("unable to start container process: %w", err)
354-
}
355350

356-
if logsDone != nil {
351+
if logsDone := parent.forwardChildLogs(); logsDone != nil {
357352
defer func() {
358353
// Wait for log forwarder to finish. This depends on
359354
// runc init closing the _LIBCONTAINER_LOGPIPE log fd.
360355
err := <-logsDone
361-
if err != nil && retErr == nil {
362-
retErr = fmt.Errorf("unable to forward init logs: %w", err)
356+
if err != nil {
357+
// runc init errors are important; make sure retErr has them.
358+
err = fmt.Errorf("runc init error(s): %w", err)
359+
if retErr != nil {
360+
retErr = fmt.Errorf("%w; %w", retErr, err)
361+
} else {
362+
retErr = err
363+
}
363364
}
364365
}()
365366
}
366367

368+
if err := parent.start(); err != nil {
369+
return fmt.Errorf("unable to start container process: %w", err)
370+
}
371+
367372
if process.Init {
368373
c.fifo.Close()
369374
if c.config.HasHook(configs.Poststart) {

libcontainer/logs/logs.go

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,16 @@ package logs
44

55
import (
66
"bufio"
7+
"bytes"
78
"encoding/json"
9+
"errors"
810
"io"
911

1012
"github.com/sirupsen/logrus"
1113
)
1214

15+
var fatalsSep = []byte("; ")
16+
1317
func ForwardLogs(logPipe io.ReadCloser) chan error {
1418
done := make(chan error, 1)
1519
s := bufio.NewScanner(logPipe)
@@ -25,24 +29,33 @@ func ForwardLogs(logPipe io.ReadCloser) chan error {
2529
}
2630

2731
go func() {
32+
fatals := []byte{}
2833
for s.Scan() {
29-
processEntry(s.Bytes(), logger)
34+
fatals = processEntry(s.Bytes(), logger, fatals)
35+
}
36+
if err := s.Err(); err != nil {
37+
logrus.Errorf("error reading from log source: %v", err)
3038
}
3139
if err := logPipe.Close(); err != nil {
3240
logrus.Errorf("error closing log source: %v", err)
3341
}
34-
// The only error we want to return is when reading from
35-
// logPipe has failed.
36-
done <- s.Err()
42+
// The only error we return is fatal messages from runc init.
43+
var err error
44+
if len(fatals) > 0 {
45+
err = errors.New(string(bytes.TrimSuffix(fatals, fatalsSep)))
46+
}
47+
done <- err
3748
close(done)
3849
}()
3950

4051
return done
4152
}
4253

43-
func processEntry(text []byte, logger *logrus.Logger) {
54+
// processEntry parses the error and either logs it via the standard logger or,
55+
// if this is a fatal error, appends its text to fatals.
56+
func processEntry(text []byte, logger *logrus.Logger, fatals []byte) []byte {
4457
if len(text) == 0 {
45-
return
58+
return fatals
4659
}
4760

4861
var jl struct {
@@ -51,8 +64,14 @@ func processEntry(text []byte, logger *logrus.Logger) {
5164
}
5265
if err := json.Unmarshal(text, &jl); err != nil {
5366
logrus.Errorf("failed to decode %q to json: %v", text, err)
54-
return
67+
return fatals
5568
}
5669

57-
logger.Log(jl.Level, jl.Msg)
70+
if jl.Level == logrus.FatalLevel {
71+
fatals = append(fatals, jl.Msg...)
72+
fatals = append(fatals, fatalsSep...)
73+
} else {
74+
logger.Log(jl.Level, jl.Msg)
75+
}
76+
return fatals
5877
}

0 commit comments

Comments
 (0)