provisioner/salt-masterless: Wait for operations to complete

Previously the provisioner did not wait until the Salt operation had completed before returning, causing some operations not to be applied, and causing the output to get swallowed.

Now we wait until the remote work is complete, and copy output into the Terraform log in a similar way as is done for other provisioners.
This commit is contained in:
Subba Rao Pasupuleti 2017-12-05 12:26:40 -05:00 committed by Martin Atkins
parent fe33661b59
commit 44cb98e04f
1 changed files with 70 additions and 5 deletions

View File

@ -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)
}
}