Commit e4e37204 authored by Mitchell Hashimoto's avatar Mitchell Hashimoto

packer/plugin: fix data race reading stdout in Client

parent a6608544
...@@ -2,7 +2,6 @@ package plugin ...@@ -2,7 +2,6 @@ package plugin
import ( import (
"bufio" "bufio"
"bytes"
"errors" "errors"
"fmt" "fmt"
"github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/packer"
...@@ -222,7 +221,7 @@ func (c *Client) Start() (address string, err error) { ...@@ -222,7 +221,7 @@ func (c *Client) Start() (address string, err error) {
fmt.Sprintf("PACKER_PLUGIN_MAX_PORT=%d", c.config.MaxPort), fmt.Sprintf("PACKER_PLUGIN_MAX_PORT=%d", c.config.MaxPort),
} }
stdout := new(bytes.Buffer) stdout_r, stdout_w := io.Pipe()
stderr_r, stderr_w := io.Pipe() stderr_r, stderr_w := io.Pipe()
cmd := c.config.Cmd cmd := c.config.Cmd
...@@ -230,7 +229,7 @@ func (c *Client) Start() (address string, err error) { ...@@ -230,7 +229,7 @@ func (c *Client) Start() (address string, err error) {
cmd.Env = append(cmd.Env, env...) cmd.Env = append(cmd.Env, env...)
cmd.Stdin = os.Stdin cmd.Stdin = os.Stdin
cmd.Stderr = stderr_w cmd.Stderr = stderr_w
cmd.Stdout = stdout cmd.Stdout = stdout_w
log.Printf("Starting plugin: %s %#v", cmd.Path, cmd.Args) log.Printf("Starting plugin: %s %#v", cmd.Path, cmd.Args)
err = cmd.Start() err = cmd.Start()
...@@ -253,9 +252,10 @@ func (c *Client) Start() (address string, err error) { ...@@ -253,9 +252,10 @@ func (c *Client) Start() (address string, err error) {
// Start goroutine to wait for process to exit // Start goroutine to wait for process to exit
go func() { go func() {
// Make sure we close the write end of our stderr listener so // Make sure we close the write end of our stderr/stdout so
// that the log goroutine ends properly. // that the readers send EOF properly.
defer stderr_w.Close() defer stderr_w.Close()
defer stdout_w.Close()
// Wait for the command to end. // Wait for the command to end.
cmd.Wait() cmd.Wait()
...@@ -271,6 +271,34 @@ func (c *Client) Start() (address string, err error) { ...@@ -271,6 +271,34 @@ func (c *Client) Start() (address string, err error) {
// Start goroutine that logs the stderr // Start goroutine that logs the stderr
go c.logStderr(stderr_r) go c.logStderr(stderr_r)
// Start a goroutine that is going to be reading the lines
// out of stdout
linesCh := make(chan []byte)
go func() {
defer close(linesCh)
buf := bufio.NewReader(stdout_r)
for {
line, err := buf.ReadBytes('\n')
if line != nil {
linesCh <- line
}
if err == io.EOF {
return
}
}
}()
// Make sure after we exit we read the lines from stdout forever
// so they dont' block since it is an io.Pipe
defer func() {
go func() {
for _ = range linesCh {
}
}()
}()
// Some channels for the next step // Some channels for the next step
timeout := time.After(c.config.StartTimeout) timeout := time.After(c.config.StartTimeout)
...@@ -281,6 +309,12 @@ func (c *Client) Start() (address string, err error) { ...@@ -281,6 +309,12 @@ func (c *Client) Start() (address string, err error) {
case <-timeout: case <-timeout:
err = errors.New("timeout while waiting for plugin to start") err = errors.New("timeout while waiting for plugin to start")
done = true done = true
case line := <-linesCh:
// Trim the address and reset the err since we were able
// to read some sort of address.
c.address = strings.TrimSpace(string(line))
address = c.address
return
default: default:
} }
...@@ -289,15 +323,6 @@ func (c *Client) Start() (address string, err error) { ...@@ -289,15 +323,6 @@ func (c *Client) Start() (address string, err error) {
done = true done = true
} }
if line, lerr := stdout.ReadBytes('\n'); lerr == nil {
// Trim the address and reset the err since we were able
// to read some sort of address.
c.address = strings.TrimSpace(string(line))
address = c.address
err = nil
break
}
// If error is nil from previously, return now // If error is nil from previously, return now
if err != nil { if err != nil {
return return
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment