fix podman top missing output flake

Sometimes there is no output displayed from the podman top command but
no error is shown either. Looking at the code I think the issue here is
that we do not wait for the output reader to end as it runs in a
different goroutine. Thus the last lines of output might be missing.

The fix is simply to wait for said goroutine to finish before returning.
While at it also fix the missing scanner error check and return the read
errors back to the caller.

[NO NEW TESTS NEEDED] It is a flake.

Fixes #19504

Signed-off-by: Paul Holzinger <pholzing@redhat.com>
This commit is contained in:
Paul Holzinger
2023-08-11 13:15:39 +02:00
parent a60bafea48
commit 4b80492bd2

View File

@ -297,19 +297,24 @@ func (c *Container) execPS(psArgs []string) ([]string, bool, error) {
if err != nil { if err != nil {
return nil, false, err return nil, false, err
} }
defer wPipe.Close()
defer rPipe.Close() defer rPipe.Close()
outErrChan := make(chan error)
stdout := []string{} stdout := []string{}
go func() { go func() {
defer close(outErrChan)
scanner := bufio.NewScanner(rPipe) scanner := bufio.NewScanner(rPipe)
for scanner.Scan() { for scanner.Scan() {
stdout = append(stdout, scanner.Text()) stdout = append(stdout, scanner.Text())
} }
if err := scanner.Err(); err != nil {
outErrChan <- err
}
}() }()
psPath, err := exec.LookPath("ps") psPath, err := exec.LookPath("ps")
if err != nil { if err != nil {
wPipe.Close()
return nil, true, err return nil, true, err
} }
args := append([]string{podmanTopCommand, strconv.Itoa(c.state.PID), psPath}, psArgs...) args := append([]string{podmanTopCommand, strconv.Itoa(c.state.PID), psPath}, psArgs...)
@ -326,6 +331,7 @@ func (c *Container) execPS(psArgs []string) ([]string, bool, error) {
retryContainerExec := true retryContainerExec := true
err = cmd.Run() err = cmd.Run()
wPipe.Close()
if err != nil { if err != nil {
exitError := &exec.ExitError{} exitError := &exec.ExitError{}
if errors.As(err, &exitError) { if errors.As(err, &exitError) {
@ -342,6 +348,10 @@ func (c *Container) execPS(psArgs []string) ([]string, bool, error) {
err = fmt.Errorf("could not reexec podman-top command: %w", err) err = fmt.Errorf("could not reexec podman-top command: %w", err)
} }
} }
if err := <-outErrChan; err != nil {
return nil, retryContainerExec, fmt.Errorf("failed to read ps stdout: %w", err)
}
return stdout, retryContainerExec, err return stdout, retryContainerExec, err
} }
@ -352,7 +362,6 @@ func (c *Container) execPSinContainer(args []string) ([]string, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
defer wPipe.Close()
defer rPipe.Close() defer rPipe.Close()
var errBuf bytes.Buffer var errBuf bytes.Buffer
@ -362,18 +371,24 @@ func (c *Container) execPSinContainer(args []string) ([]string, error) {
streams.AttachOutput = true streams.AttachOutput = true
streams.AttachError = true streams.AttachError = true
outErrChan := make(chan error)
stdout := []string{} stdout := []string{}
go func() { go func() {
defer close(outErrChan)
scanner := bufio.NewScanner(rPipe) scanner := bufio.NewScanner(rPipe)
for scanner.Scan() { for scanner.Scan() {
stdout = append(stdout, scanner.Text()) stdout = append(stdout, scanner.Text())
} }
if err := scanner.Err(); err != nil {
outErrChan <- err
}
}() }()
cmd := append([]string{"ps"}, args...) cmd := append([]string{"ps"}, args...)
config := new(ExecConfig) config := new(ExecConfig)
config.Command = cmd config.Command = cmd
ec, err := c.Exec(config, streams, nil) ec, err := c.Exec(config, streams, nil)
wPipe.Close()
if err != nil { if err != nil {
return nil, err return nil, err
} else if ec != 0 { } else if ec != 0 {
@ -386,5 +401,8 @@ func (c *Container) execPSinContainer(args []string) ([]string, error) {
logrus.Debugf(errBuf.String()) logrus.Debugf(errBuf.String())
} }
if err := <-outErrChan; err != nil {
return nil, fmt.Errorf("failed to read ps stdout: %w", err)
}
return stdout, nil return stdout, nil
} }