Skip to content

Commit

Permalink
libc/logs: wait for init/nsenter logs
Browse files Browse the repository at this point in the history
Adding more nsenter debug logging revealed a bug: some logs were lost,
resulting in random failures of debug.bats tests (usually the ones
that write to a file).

The bug happens because the main thread does not wait for the
ForwardLogs goroutine to do its work, and it is reproducible with
a short-lived container and a (relatively) slow operation of
writing logs to a file.

Obviously, a way to fix this is to make the main thread wait for the
ForwardLogs goroutine. This works only if we explicitly close the
writing end of a log pipe, so this closing had to be added.

Signed-off-by: Kir Kolyshkin <[email protected]>
  • Loading branch information
kolyshkin committed Jul 14, 2020
1 parent 13d3cef commit 634317d
Show file tree
Hide file tree
Showing 6 changed files with 22 additions and 10 deletions.
4 changes: 4 additions & 0 deletions init.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
_ "github.com/opencontainers/runc/libcontainer/nsenter"
"github.com/sirupsen/logrus"
"github.com/urfave/cli"
"golang.org/x/sys/unix"
)

func init() {
Expand Down Expand Up @@ -38,6 +39,9 @@ func init() {
panic(fmt.Sprintf("libcontainer: failed to configure logging: %v", err))
}
logrus.Debug("child process in init()")

// let ForwardLogs exit. Note no more logrus logging is possible after
unix.Close(logPipeFd)
}
}

Expand Down
5 changes: 4 additions & 1 deletion libcontainer/container_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,8 @@ func (c *linuxContainer) start(process *Process) error {
if err != nil {
return newSystemErrorWithCause(err, "creating new parent process")
}
parent.forwardChildLogs()
logsDone := make(chan struct{})
parent.forwardChildLogs(logsDone)
if err := parent.start(); err != nil {
// terminate the process to ensure that it properly is reaped.
if err := ignoreTerminateErrors(parent.terminate()); err != nil {
Expand Down Expand Up @@ -395,6 +396,8 @@ func (c *linuxContainer) start(process *Process) error {
}
}
}
// wait for forwardChildLogs to finish
<-logsDone
return nil
}

Expand Down
3 changes: 2 additions & 1 deletion libcontainer/container_linux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,8 @@ func (m *mockProcess) externalDescriptors() []string {
func (m *mockProcess) setExternalDescriptors(newFds []string) {
}

func (m *mockProcess) forwardChildLogs() {
func (m *mockProcess) forwardChildLogs(done chan struct{}) {
close(done)
}

func TestGetContainerPids(t *testing.T) {
Expand Down
3 changes: 2 additions & 1 deletion libcontainer/logs/logs.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ type Config struct {
LogPipeFd int
}

func ForwardLogs(logPipe io.Reader) {
func ForwardLogs(logPipe io.Reader, done chan struct{}) {
s := bufio.NewScanner(logPipe)
for s.Scan() {
processEntry(s.Bytes())
Expand All @@ -35,6 +35,7 @@ func ForwardLogs(logPipe io.Reader) {
} else {
logrus.Debugf("log pipe closed")
}
close(done)
}

func processEntry(text []byte) {
Expand Down
11 changes: 6 additions & 5 deletions libcontainer/process_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ type parentProcess interface {

setExternalDescriptors(fds []string)

forwardChildLogs()
forwardChildLogs(done chan struct{})
}

type filePair struct {
Expand All @@ -70,6 +70,7 @@ type setnsProcess struct {
process *Process
bootstrapData io.Reader
initProcessPid int
logsDone chan struct{}
}

func (p *setnsProcess) startTime() (uint64, error) {
Expand Down Expand Up @@ -235,8 +236,8 @@ func (p *setnsProcess) setExternalDescriptors(newFds []string) {
p.fds = newFds
}

func (p *setnsProcess) forwardChildLogs() {
go logs.ForwardLogs(p.logFilePair.parent)
func (p *setnsProcess) forwardChildLogs(done chan struct{}) {
go logs.ForwardLogs(p.logFilePair.parent, done)
}

type initProcess struct {
Expand Down Expand Up @@ -547,8 +548,8 @@ func (p *initProcess) setExternalDescriptors(newFds []string) {
p.fds = newFds
}

func (p *initProcess) forwardChildLogs() {
go logs.ForwardLogs(p.logFilePair.parent)
func (p *initProcess) forwardChildLogs(done chan struct{}) {
go logs.ForwardLogs(p.logFilePair.parent, done)
}

func getPipeFds(pid int) ([]string, error) {
Expand Down
6 changes: 4 additions & 2 deletions libcontainer/restored_process.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@ func (p *restoredProcess) setExternalDescriptors(newFds []string) {
p.fds = newFds
}

func (p *restoredProcess) forwardChildLogs() {
func (p *restoredProcess) forwardChildLogs(done chan struct{}) {
close(done)
}

// nonChildProcess represents a process where the calling process is not
Expand Down Expand Up @@ -125,5 +126,6 @@ func (p *nonChildProcess) setExternalDescriptors(newFds []string) {
p.fds = newFds
}

func (p *nonChildProcess) forwardChildLogs() {
func (p *nonChildProcess) forwardChildLogs(done chan struct{}) {
close(done)
}

0 comments on commit 634317d

Please sign in to comment.