From b615faffb6ac71aae53fb1aa8b661bad48ad38d9 Mon Sep 17 00:00:00 2001 From: Subba Rao Pasupuleti Date: Sun, 19 Nov 2017 15:20:19 -0500 Subject: [PATCH 1/2] wait until salt install/run finished --- builtin/provisioners/salt-masterless/resource_provisioner.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/builtin/provisioners/salt-masterless/resource_provisioner.go b/builtin/provisioners/salt-masterless/resource_provisioner.go index b81a3703789c..d8f7aff43d74 100644 --- a/builtin/provisioners/salt-masterless/resource_provisioner.go +++ b/builtin/provisioners/salt-masterless/resource_provisioner.go @@ -141,13 +141,16 @@ func applyFn(ctx context.Context) error { if err = comm.Start(cmd); err != nil { return fmt.Errorf("Unable to download Salt: %s", err) } + cmd.Wait() cmd = &remote.Cmd{ Command: fmt.Sprintf("%s /tmp/install_salt.sh %s", p.sudo("sh"), p.BootstrapArgs), } + 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) } + cmd.Wait() } o.Output(fmt.Sprintf("Creating remote temporary directory: %s", p.TempConfigDir)) @@ -221,6 +224,7 @@ func applyFn(ctx context.Context) error { return fmt.Errorf("Error executing salt-call: %s", err) } + cmd.Wait() return nil } From b0e8dfc2cb61fbafbcd164b3bbc3a4a9fa1e7574 Mon Sep 17 00:00:00 2001 From: Subba Rao Pasupuleti Date: Sun, 19 Nov 2017 15:53:08 -0500 Subject: [PATCH 2/2] pipe remote command output to stdout --- .../salt-masterless/resource_provisioner.go | 77 +++++++++++++++++-- 1 file changed, 69 insertions(+), 8 deletions(-) diff --git a/builtin/provisioners/salt-masterless/resource_provisioner.go b/builtin/provisioners/salt-masterless/resource_provisioner.go index d8f7aff43d74..70942c5d7b6b 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,18 +141,47 @@ 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) } - cmd.Wait() + + 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 } - cmd.Wait() } o.Output(fmt.Sprintf("Creating remote temporary directory: %s", p.TempConfigDir)) @@ -215,18 +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) + } } - cmd.Wait() + // 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 @@ -470,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) + } +}