update the chef and habitat error handling

Use the new ExitStatus method, and also check the cmd.Err() method for
errors.

Remove leaks from the output goroutines in both provisioners by
deferring their cleanup, and returning early on all error conditions.
This commit is contained in:
James Bardin 2018-03-15 12:55:57 -04:00
parent a715430d24
commit a1061ed931
2 changed files with 26 additions and 19 deletions

View File

@ -684,6 +684,13 @@ func (p *provisioner) runCommand(o terraform.UIOutput, comm communicator.Communi
errDoneCh := make(chan struct{}) errDoneCh := make(chan struct{})
go p.copyOutput(o, outR, outDoneCh) go p.copyOutput(o, outR, outDoneCh)
go p.copyOutput(o, errR, errDoneCh) go p.copyOutput(o, errR, errDoneCh)
go func() {
// Wait for output to clean up
outW.Close()
errW.Close()
<-outDoneCh
<-errDoneCh
}()
cmd := &remote.Cmd{ cmd := &remote.Cmd{
Command: command, Command: command,
@ -697,18 +704,15 @@ func (p *provisioner) runCommand(o terraform.UIOutput, comm communicator.Communi
} }
cmd.Wait() cmd.Wait()
if cmd.ExitStatus != 0 { if cmd.Err() != nil {
err = fmt.Errorf( return cmd.Err()
"Command %q exited with non-zero exit status: %d", cmd.Command, cmd.ExitStatus)
} }
// Wait for output to clean up if cmd.ExitStatus() != 0 {
outW.Close() return fmt.Errorf("Command %q exited with non-zero exit status: %d", cmd.Command, cmd.ExitStatus())
errW.Close() }
<-outDoneCh
<-errDoneCh
return err return nil
} }
func (p *provisioner) copyOutput(o terraform.UIOutput, r io.Reader, doneCh chan<- struct{}) { func (p *provisioner) copyOutput(o terraform.UIOutput, r io.Reader, doneCh chan<- struct{}) {

View File

@ -740,12 +740,17 @@ func (p *provisioner) copyOutput(o terraform.UIOutput, r io.Reader, doneCh chan<
func (p *provisioner) runCommand(o terraform.UIOutput, comm communicator.Communicator, command string) error { func (p *provisioner) runCommand(o terraform.UIOutput, comm communicator.Communicator, command string) error {
outR, outW := io.Pipe() outR, outW := io.Pipe()
errR, errW := io.Pipe() errR, errW := io.Pipe()
var err error
outDoneCh := make(chan struct{}) outDoneCh := make(chan struct{})
errDoneCh := make(chan struct{}) errDoneCh := make(chan struct{})
go p.copyOutput(o, outR, outDoneCh) go p.copyOutput(o, outR, outDoneCh)
go p.copyOutput(o, errR, errDoneCh) go p.copyOutput(o, errR, errDoneCh)
defer func() {
outW.Close()
errW.Close()
<-outDoneCh
<-errDoneCh
}()
cmd := &remote.Cmd{ cmd := &remote.Cmd{
Command: command, Command: command,
@ -753,22 +758,20 @@ func (p *provisioner) runCommand(o terraform.UIOutput, comm communicator.Communi
Stderr: errW, Stderr: errW,
} }
if err = comm.Start(cmd); err != nil { if err := comm.Start(cmd); err != nil {
return fmt.Errorf("Error executing command %q: %v", cmd.Command, err) return fmt.Errorf("Error executing command %q: %v", cmd.Command, err)
} }
cmd.Wait() cmd.Wait()
if cmd.ExitStatus != 0 { if cmd.Err() != nil {
err = fmt.Errorf( return cmd.Err()
"Command %q exited with non-zero exit status: %d", cmd.Command, cmd.ExitStatus)
} }
outW.Close() if cmd.ExitStatus() != 0 {
errW.Close() return fmt.Errorf("Command %q exited with non-zero exit status: %d", cmd.Command, cmd.ExitStatus())
<-outDoneCh }
<-errDoneCh
return err return nil
} }
func getBindFromString(bind string) (Bind, error) { func getBindFromString(bind string) (Bind, error) {