diff --git a/builtin/provisioners/salt-masterless/resource_provisioner.go b/builtin/provisioners/salt-masterless/resource_provisioner.go index b81a37037..70942c5d7 100644 --- a/builtin/provisioners/salt-masterless/resource_provisioner.go +++ b/builtin/provisioners/salt-masterless/resource_provisioner.go @@ -10,6 +10,7 @@ import ( "context" "errors" "fmt" + "io" "os" "path/filepath" @@ -17,6 +18,7 @@ import ( "github.com/hashicorp/terraform/communicator/remote" "github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/terraform" + linereader "github.com/mitchellh/go-linereader" ) type provisionFn func(terraform.UIOutput, communicator.Communicator) error @@ -139,14 +141,46 @@ func applyFn(ctx context.Context) error { } o.Output(fmt.Sprintf("Downloading saltstack bootstrap to /tmp/install_salt.sh")) if err = comm.Start(cmd); err != nil { - return fmt.Errorf("Unable to download Salt: %s", err) + err = fmt.Errorf("Unable to download Salt: %s", err) } + + if err == nil { + cmd.Wait() + if cmd.ExitStatus != 0 { + err = fmt.Errorf("Script exited with non-zero exit status: %d", cmd.ExitStatus) + } + } + + outR, outW := io.Pipe() + errR, errW := io.Pipe() + outDoneCh := make(chan struct{}) + errDoneCh := make(chan struct{}) + go copyOutput(o, outR, outDoneCh) + go copyOutput(o, errR, errDoneCh) cmd = &remote.Cmd{ Command: fmt.Sprintf("%s /tmp/install_salt.sh %s", p.sudo("sh"), p.BootstrapArgs), + Stdout: outW, + Stderr: errW, } + o.Output(fmt.Sprintf("Installing Salt with command %s", cmd.Command)) if err = comm.Start(cmd); err != nil { - return fmt.Errorf("Unable to install Salt: %s", err) + err = fmt.Errorf("Unable to install Salt: %s", err) + } + + if err == nil { + cmd.Wait() + if cmd.ExitStatus != 0 { + err = fmt.Errorf("Script exited with non-zero exit status: %d", cmd.ExitStatus) + } + } + // Wait for output to clean up + outW.Close() + errW.Close() + <-outDoneCh + <-errDoneCh + if err != nil { + return err } } @@ -212,17 +246,39 @@ func applyFn(ctx context.Context) error { } } + outR, outW := io.Pipe() + errR, errW := io.Pipe() + outDoneCh := make(chan struct{}) + errDoneCh := make(chan struct{}) + + go copyOutput(o, outR, outDoneCh) + go copyOutput(o, errR, errDoneCh) o.Output(fmt.Sprintf("Running: salt-call --local %s", p.CmdArgs)) - cmd := &remote.Cmd{Command: p.sudo(fmt.Sprintf("salt-call --local %s", p.CmdArgs))} + cmd := &remote.Cmd{ + Command: p.sudo(fmt.Sprintf("salt-call --local %s", p.CmdArgs)), + Stdout: outW, + Stderr: errW, + } if err = comm.Start(cmd); err != nil || cmd.ExitStatus != 0 { if err == nil { err = fmt.Errorf("Bad exit status: %d", cmd.ExitStatus) } - return fmt.Errorf("Error executing salt-call: %s", err) + err = fmt.Errorf("Error executing salt-call: %s", err) } + if err == nil { + cmd.Wait() + if cmd.ExitStatus != 0 { + err = fmt.Errorf("Script exited with non-zero exit status: %d", cmd.ExitStatus) + } + } + // Wait for output to clean up + outW.Close() + errW.Close() + <-outDoneCh + <-errDoneCh - return nil + return err } // Prepends sudo to supplied command if config says to @@ -466,3 +522,12 @@ func decodeConfig(d *schema.ResourceData) (*provisioner, error) { return p, nil } + +func copyOutput( + o terraform.UIOutput, r io.Reader, doneCh chan<- struct{}) { + defer close(doneCh) + lr := linereader.New(r) + for line := range lr.Ch { + o.Output(line) + } +}