allow a provisioner to timeout
* I had to contextualise Communicator.Start and RemoteCmd.StartWithUi NOTE: Communicator.Start starts a RemoteCmd but RemoteCmd.StartWithUi will run the cmd and wait for a return, so I renamed StartWithUi to RunWithUi so that the intent is clearer. Ideally in the future RunWithUi will be named back to StartWithUi and the exit status or wait funcs of the command will allow to wait for a return. If you do so please read carrefully https://golang.org/pkg/os/exec/#Cmd.Stdout to avoid a deadlock * cmd.ExitStatus to cmd.ExitStatus() is now blocking to avoid race conditions * also had to simplify StartWithUi
This commit is contained in:
parent
f7cd2b9334
commit
f555e7a9f2
|
@ -2,6 +2,7 @@ package chroot
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
|
@ -23,7 +24,7 @@ type Communicator struct {
|
||||||
CmdWrapper CommandWrapper
|
CmdWrapper CommandWrapper
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Communicator) Start(cmd *packer.RemoteCmd) error {
|
func (c *Communicator) Start(ctx context.Context, cmd *packer.RemoteCmd) error {
|
||||||
// need extra escapes for the command since we're wrapping it in quotes
|
// need extra escapes for the command since we're wrapping it in quotes
|
||||||
cmd.Command = strconv.Quote(cmd.Command)
|
cmd.Command = strconv.Quote(cmd.Command)
|
||||||
command, err := c.CmdWrapper(
|
command, err := c.CmdWrapper(
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package chroot
|
package chroot
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
sl "github.com/hashicorp/packer/common/shell-local"
|
sl "github.com/hashicorp/packer/common/shell-local"
|
||||||
|
@ -9,6 +10,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func RunLocalCommands(commands []string, wrappedCommand CommandWrapper, ictx interpolate.Context, ui packer.Ui) error {
|
func RunLocalCommands(commands []string, wrappedCommand CommandWrapper, ictx interpolate.Context, ui packer.Ui) error {
|
||||||
|
ctx := context.TODO()
|
||||||
for _, rawCmd := range commands {
|
for _, rawCmd := range commands {
|
||||||
intCmd, err := interpolate.Render(rawCmd, &ictx)
|
intCmd, err := interpolate.Render(rawCmd, &ictx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -25,13 +27,13 @@ func RunLocalCommands(commands []string, wrappedCommand CommandWrapper, ictx int
|
||||||
ExecuteCommand: []string{"sh", "-c", command},
|
ExecuteCommand: []string{"sh", "-c", command},
|
||||||
}
|
}
|
||||||
cmd := &packer.RemoteCmd{Command: command}
|
cmd := &packer.RemoteCmd{Command: command}
|
||||||
if err := cmd.StartWithUi(comm, ui); err != nil {
|
if err := cmd.RunWithUi(ctx, comm, ui); err != nil {
|
||||||
return fmt.Errorf("Error executing command: %s", err)
|
return fmt.Errorf("Error executing command: %s", err)
|
||||||
}
|
}
|
||||||
if cmd.ExitStatus != 0 {
|
if cmd.ExitStatus() != 0 {
|
||||||
return fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"Received non-zero exit code %d from command: %s",
|
"Received non-zero exit code %d from command: %s",
|
||||||
cmd.ExitStatus,
|
cmd.ExitStatus(),
|
||||||
command)
|
command)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,13 +59,13 @@ func (s *StepBundleVolume) Run(ctx context.Context, state multistep.StateBag) mu
|
||||||
ui.Say(fmt.Sprintf("Running: %s", config.BundleVolCommand))
|
ui.Say(fmt.Sprintf("Running: %s", config.BundleVolCommand))
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := cmd.StartWithUi(comm, ui); err != nil {
|
if err := cmd.RunWithUi(ctx, comm, ui); err != nil {
|
||||||
state.Put("error", fmt.Errorf("Error bundling volume: %s", err))
|
state.Put("error", fmt.Errorf("Error bundling volume: %s", err))
|
||||||
ui.Error(state.Get("error").(error).Error())
|
ui.Error(state.Get("error").(error).Error())
|
||||||
return multistep.ActionHalt
|
return multistep.ActionHalt
|
||||||
}
|
}
|
||||||
|
|
||||||
if cmd.ExitStatus != 0 {
|
if cmd.ExitStatus() != 0 {
|
||||||
state.Put("error", fmt.Errorf(
|
state.Put("error", fmt.Errorf(
|
||||||
"Volume bundling failed. Please see the output above for more\n"+
|
"Volume bundling failed. Please see the output above for more\n"+
|
||||||
"details on what went wrong.\n\n"+
|
"details on what went wrong.\n\n"+
|
||||||
|
|
|
@ -69,14 +69,14 @@ func (s *StepUploadBundle) Run(ctx context.Context, state multistep.StateBag) mu
|
||||||
ui.Say(fmt.Sprintf("Running: %s", config.BundleUploadCommand))
|
ui.Say(fmt.Sprintf("Running: %s", config.BundleUploadCommand))
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := cmd.StartWithUi(comm, ui); err != nil {
|
if err := cmd.RunWithUi(ctx, comm, ui); err != nil {
|
||||||
state.Put("error", fmt.Errorf("Error uploading volume: %s", err))
|
state.Put("error", fmt.Errorf("Error uploading volume: %s", err))
|
||||||
ui.Error(state.Get("error").(error).Error())
|
ui.Error(state.Get("error").(error).Error())
|
||||||
return multistep.ActionHalt
|
return multistep.ActionHalt
|
||||||
}
|
}
|
||||||
|
|
||||||
if cmd.ExitStatus != 0 {
|
if cmd.ExitStatus() != 0 {
|
||||||
if cmd.ExitStatus == 3 {
|
if cmd.ExitStatus() == 3 {
|
||||||
ui.Error(fmt.Sprintf("Please check that the bucket `%s` "+
|
ui.Error(fmt.Sprintf("Please check that the bucket `%s` "+
|
||||||
"does not exist, or exists and is writable. This error "+
|
"does not exist, or exists and is writable. This error "+
|
||||||
"indicates that the bucket may be owned by somebody else.",
|
"indicates that the bucket may be owned by somebody else.",
|
||||||
|
|
|
@ -2,6 +2,7 @@ package docker
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"archive/tar"
|
"archive/tar"
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
@ -28,7 +29,9 @@ type Communicator struct {
|
||||||
EntryPoint []string
|
EntryPoint []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Communicator) Start(remote *packer.RemoteCmd) error {
|
var _ packer.Communicator = new(Communicator)
|
||||||
|
|
||||||
|
func (c *Communicator) Start(ctx context.Context, remote *packer.RemoteCmd) error {
|
||||||
dockerArgs := []string{
|
dockerArgs := []string{
|
||||||
"exec",
|
"exec",
|
||||||
"-i",
|
"-i",
|
||||||
|
|
|
@ -15,10 +15,6 @@ import (
|
||||||
"github.com/hashicorp/packer/template"
|
"github.com/hashicorp/packer/template"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCommunicator_impl(t *testing.T) {
|
|
||||||
var _ packer.Communicator = new(Communicator)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestUploadDownload verifies that basic upload / download functionality works
|
// TestUploadDownload verifies that basic upload / download functionality works
|
||||||
func TestUploadDownload(t *testing.T) {
|
func TestUploadDownload(t *testing.T) {
|
||||||
ui := packer.TestUi(t)
|
ui := packer.TestUi(t)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package hyperone
|
package hyperone
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
@ -20,7 +21,7 @@ type ChrootCommunicator struct {
|
||||||
Wrapped packer.Communicator
|
Wrapped packer.Communicator
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ChrootCommunicator) Start(cmd *packer.RemoteCmd) error {
|
func (c *ChrootCommunicator) Start(ctx context.Context, cmd *packer.RemoteCmd) error {
|
||||||
command := strconv.Quote(cmd.Command)
|
command := strconv.Quote(cmd.Command)
|
||||||
chrootCommand, err := c.CmdWrapper(
|
chrootCommand, err := c.CmdWrapper(
|
||||||
fmt.Sprintf("sudo chroot %s /bin/sh -c %s", c.Chroot, command))
|
fmt.Sprintf("sudo chroot %s /bin/sh -c %s", c.Chroot, command))
|
||||||
|
@ -30,7 +31,7 @@ func (c *ChrootCommunicator) Start(cmd *packer.RemoteCmd) error {
|
||||||
|
|
||||||
cmd.Command = chrootCommand
|
cmd.Command = chrootCommand
|
||||||
|
|
||||||
return c.Wrapped.Start(cmd)
|
return c.Wrapped.Start(ctx, cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ChrootCommunicator) Upload(dst string, r io.Reader, fi *os.FileInfo) error {
|
func (c *ChrootCommunicator) Upload(dst string, r io.Reader, fi *os.FileInfo) error {
|
||||||
|
|
|
@ -2,6 +2,7 @@ package hyperone
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -22,6 +23,7 @@ func formatOpenAPIError(err error) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func runCommands(commands []string, ictx interpolate.Context, state multistep.StateBag) error {
|
func runCommands(commands []string, ictx interpolate.Context, state multistep.StateBag) error {
|
||||||
|
ctx := context.TODO()
|
||||||
ui := state.Get("ui").(packer.Ui)
|
ui := state.Get("ui").(packer.Ui)
|
||||||
wrappedCommand := state.Get("wrappedCommand").(CommandWrapper)
|
wrappedCommand := state.Get("wrappedCommand").(CommandWrapper)
|
||||||
comm := state.Get("communicator").(packer.Communicator)
|
comm := state.Get("communicator").(packer.Communicator)
|
||||||
|
@ -43,15 +45,15 @@ func runCommands(commands []string, ictx interpolate.Context, state multistep.St
|
||||||
|
|
||||||
ui.Say(fmt.Sprintf("Executing command: %s", command))
|
ui.Say(fmt.Sprintf("Executing command: %s", command))
|
||||||
|
|
||||||
err = remoteCmd.StartWithUi(comm, ui)
|
err = remoteCmd.RunWithUi(ctx, comm, ui)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error running remote cmd: %s", err)
|
return fmt.Errorf("error running remote cmd: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if remoteCmd.ExitStatus != 0 {
|
if remoteCmd.ExitStatus() != 0 {
|
||||||
return fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"received non-zero exit code %d from command: %s",
|
"received non-zero exit code %d from command: %s",
|
||||||
remoteCmd.ExitStatus,
|
remoteCmd.ExitStatus(),
|
||||||
command)
|
command)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,6 +61,7 @@ func runCommands(commands []string, ictx interpolate.Context, state multistep.St
|
||||||
}
|
}
|
||||||
|
|
||||||
func captureOutput(command string, state multistep.StateBag) (string, error) {
|
func captureOutput(command string, state multistep.StateBag) (string, error) {
|
||||||
|
ctx := context.TODO()
|
||||||
comm := state.Get("communicator").(packer.Communicator)
|
comm := state.Get("communicator").(packer.Communicator)
|
||||||
|
|
||||||
var stdout bytes.Buffer
|
var stdout bytes.Buffer
|
||||||
|
@ -69,16 +72,16 @@ func captureOutput(command string, state multistep.StateBag) (string, error) {
|
||||||
|
|
||||||
log.Println(fmt.Sprintf("Executing command: %s", command))
|
log.Println(fmt.Sprintf("Executing command: %s", command))
|
||||||
|
|
||||||
err := comm.Start(remoteCmd)
|
err := comm.Start(ctx, remoteCmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("error running remote cmd: %s", err)
|
return "", fmt.Errorf("error running remote cmd: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
remoteCmd.Wait()
|
remoteCmd.Wait()
|
||||||
if remoteCmd.ExitStatus != 0 {
|
if remoteCmd.ExitStatus() != 0 {
|
||||||
return "", fmt.Errorf(
|
return "", fmt.Errorf(
|
||||||
"received non-zero exit code %d from command: %s",
|
"received non-zero exit code %d from command: %s",
|
||||||
remoteCmd.ExitStatus,
|
remoteCmd.ExitStatus(),
|
||||||
command)
|
command)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,7 @@ func (s *StepShutdown) Run(ctx context.Context, state multistep.StateBag) multis
|
||||||
Stdout: &stdout,
|
Stdout: &stdout,
|
||||||
Stderr: &stderr,
|
Stderr: &stderr,
|
||||||
}
|
}
|
||||||
if err := comm.Start(cmd); err != nil {
|
if err := comm.Start(ctx, cmd); err != nil {
|
||||||
err := fmt.Errorf("Failed to send shutdown command: %s", err)
|
err := fmt.Errorf("Failed to send shutdown command: %s", err)
|
||||||
state.Put("error", err)
|
state.Put("error", err)
|
||||||
ui.Error(err.Error())
|
ui.Error(err.Error())
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package lxc
|
package lxc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
@ -22,7 +23,7 @@ type LxcAttachCommunicator struct {
|
||||||
CmdWrapper CommandWrapper
|
CmdWrapper CommandWrapper
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *LxcAttachCommunicator) Start(cmd *packer.RemoteCmd) error {
|
func (c *LxcAttachCommunicator) Start(ctx context.Context, cmd *packer.RemoteCmd) error {
|
||||||
localCmd, err := c.Execute(cmd.Command)
|
localCmd, err := c.Execute(cmd.Command)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package lxd
|
package lxd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
|
@ -17,7 +18,7 @@ type Communicator struct {
|
||||||
CmdWrapper CommandWrapper
|
CmdWrapper CommandWrapper
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Communicator) Start(cmd *packer.RemoteCmd) error {
|
func (c *Communicator) Start(ctx context.Context, cmd *packer.RemoteCmd) error {
|
||||||
localCmd, err := c.Execute(cmd.Command)
|
localCmd, err := c.Execute(cmd.Command)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -55,11 +56,13 @@ func (c *Communicator) Start(cmd *packer.RemoteCmd) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Communicator) Upload(dst string, r io.Reader, fi *os.FileInfo) error {
|
func (c *Communicator) Upload(dst string, r io.Reader, fi *os.FileInfo) error {
|
||||||
|
ctx := context.TODO()
|
||||||
|
|
||||||
fileDestination := filepath.Join(c.ContainerName, dst)
|
fileDestination := filepath.Join(c.ContainerName, dst)
|
||||||
// find out if the place we are pushing to is a directory
|
// find out if the place we are pushing to is a directory
|
||||||
testDirectoryCommand := fmt.Sprintf(`test -d "%s"`, dst)
|
testDirectoryCommand := fmt.Sprintf(`test -d "%s"`, dst)
|
||||||
cmd := &packer.RemoteCmd{Command: testDirectoryCommand}
|
cmd := &packer.RemoteCmd{Command: testDirectoryCommand}
|
||||||
err := c.Start(cmd)
|
err := c.Start(ctx, cmd)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Unable to check whether remote path is a dir: %s", err)
|
log.Printf("Unable to check whether remote path is a dir: %s", err)
|
||||||
|
@ -67,7 +70,7 @@ func (c *Communicator) Upload(dst string, r io.Reader, fi *os.FileInfo) error {
|
||||||
}
|
}
|
||||||
cmd.Wait()
|
cmd.Wait()
|
||||||
|
|
||||||
if cmd.ExitStatus == 0 {
|
if cmd.ExitStatus() == 0 {
|
||||||
log.Printf("path is a directory; copying file into directory.")
|
log.Printf("path is a directory; copying file into directory.")
|
||||||
fileDestination = filepath.Join(c.ContainerName, dst, (*fi).Name())
|
fileDestination = filepath.Join(c.ContainerName, dst, (*fi).Name())
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,15 +66,15 @@ func (s *stepUploadImage) Run(ctx context.Context, state multistep.StateBag) mul
|
||||||
cmd := &packer.RemoteCmd{
|
cmd := &packer.RemoteCmd{
|
||||||
Command: fmt.Sprintf("sudo /bin/sh %s", dest),
|
Command: fmt.Sprintf("sudo /bin/sh %s", dest),
|
||||||
}
|
}
|
||||||
if err := cmd.StartWithUi(comm, ui); err != nil {
|
if err := cmd.RunWithUi(ctx, comm, ui); err != nil {
|
||||||
err = fmt.Errorf("Problem creating image`: %s", err)
|
err = fmt.Errorf("Problem creating image`: %s", err)
|
||||||
ui.Error(err.Error())
|
ui.Error(err.Error())
|
||||||
state.Put("error", err)
|
state.Put("error", err)
|
||||||
return multistep.ActionHalt
|
return multistep.ActionHalt
|
||||||
}
|
}
|
||||||
|
|
||||||
if cmd.ExitStatus != 0 {
|
if cmd.ExitStatus() != 0 {
|
||||||
err = fmt.Errorf("Create Disk Image command failed with exit code %d", cmd.ExitStatus)
|
err = fmt.Errorf("Create Disk Image command failed with exit code %d", cmd.ExitStatus())
|
||||||
ui.Error(err.Error())
|
ui.Error(err.Error())
|
||||||
state.Put("error", err)
|
state.Put("error", err)
|
||||||
return multistep.ActionHalt
|
return multistep.ActionHalt
|
||||||
|
|
|
@ -45,7 +45,7 @@ func (s *StepShutdown) Run(ctx context.Context, state multistep.StateBag) multis
|
||||||
Stdout: &stdout,
|
Stdout: &stdout,
|
||||||
Stderr: &stderr,
|
Stderr: &stderr,
|
||||||
}
|
}
|
||||||
if err := comm.Start(cmd); err != nil {
|
if err := comm.Start(ctx, cmd); err != nil {
|
||||||
err := fmt.Errorf("Failed to send shutdown command: %s", err)
|
err := fmt.Errorf("Failed to send shutdown command: %s", err)
|
||||||
state.Put("error", err)
|
state.Put("error", err)
|
||||||
ui.Error(err.Error())
|
ui.Error(err.Error())
|
||||||
|
|
|
@ -52,7 +52,7 @@ func (s *stepShutdown) Run(ctx context.Context, state multistep.StateBag) multis
|
||||||
ui.Say("Gracefully halting virtual machine...")
|
ui.Say("Gracefully halting virtual machine...")
|
||||||
log.Printf("Executing shutdown command: %s", config.ShutdownCommand)
|
log.Printf("Executing shutdown command: %s", config.ShutdownCommand)
|
||||||
cmd := &packer.RemoteCmd{Command: config.ShutdownCommand}
|
cmd := &packer.RemoteCmd{Command: config.ShutdownCommand}
|
||||||
if err := cmd.StartWithUi(comm, ui); err != nil {
|
if err := cmd.RunWithUi(ctx, comm, ui); err != nil {
|
||||||
err := fmt.Errorf("Failed to send shutdown command: %s", err)
|
err := fmt.Errorf("Failed to send shutdown command: %s", err)
|
||||||
state.Put("error", err)
|
state.Put("error", err)
|
||||||
ui.Error(err.Error())
|
ui.Error(err.Error())
|
||||||
|
|
|
@ -38,7 +38,7 @@ func (s *StepShutdown) Run(ctx context.Context, state multistep.StateBag) multis
|
||||||
ui.Say("Gracefully halting virtual machine...")
|
ui.Say("Gracefully halting virtual machine...")
|
||||||
log.Printf("Executing shutdown command: %s", s.Command)
|
log.Printf("Executing shutdown command: %s", s.Command)
|
||||||
cmd := &packer.RemoteCmd{Command: s.Command}
|
cmd := &packer.RemoteCmd{Command: s.Command}
|
||||||
if err := cmd.StartWithUi(comm, ui); err != nil {
|
if err := cmd.RunWithUi(ctx, comm, ui); err != nil {
|
||||||
err := fmt.Errorf("Failed to send shutdown command: %s", err)
|
err := fmt.Errorf("Failed to send shutdown command: %s", err)
|
||||||
state.Put("error", err)
|
state.Put("error", err)
|
||||||
ui.Error(err.Error())
|
ui.Error(err.Error())
|
||||||
|
|
|
@ -687,6 +687,7 @@ func (d *ESX5Driver) VerifyChecksum(ctype string, hash string, file string) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *ESX5Driver) ssh(command string, stdin io.Reader) (*bytes.Buffer, error) {
|
func (d *ESX5Driver) ssh(command string, stdin io.Reader) (*bytes.Buffer, error) {
|
||||||
|
ctx := context.TODO()
|
||||||
var stdout, stderr bytes.Buffer
|
var stdout, stderr bytes.Buffer
|
||||||
|
|
||||||
cmd := &packer.RemoteCmd{
|
cmd := &packer.RemoteCmd{
|
||||||
|
@ -696,14 +697,14 @@ func (d *ESX5Driver) ssh(command string, stdin io.Reader) (*bytes.Buffer, error)
|
||||||
Stdin: stdin,
|
Stdin: stdin,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := d.comm.Start(cmd)
|
err := d.comm.Start(ctx, cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.Wait()
|
cmd.Wait()
|
||||||
|
|
||||||
if cmd.ExitStatus != 0 {
|
if cmd.ExitStatus() != 0 {
|
||||||
err = fmt.Errorf("'%s'\n\nStdout: %s\n\nStderr: %s",
|
err = fmt.Errorf("'%s'\n\nStdout: %s\n\nStderr: %s",
|
||||||
cmd.Command, stdout.String(), stderr.String())
|
cmd.Command, stdout.String(), stderr.String())
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -51,7 +51,7 @@ func (s *StepShutdown) Run(ctx context.Context, state multistep.StateBag) multis
|
||||||
Stdout: &stdout,
|
Stdout: &stdout,
|
||||||
Stderr: &stderr,
|
Stderr: &stderr,
|
||||||
}
|
}
|
||||||
if err := comm.Start(cmd); err != nil {
|
if err := comm.Start(ctx, cmd); err != nil {
|
||||||
err := fmt.Errorf("Failed to send shutdown command: %s", err)
|
err := fmt.Errorf("Failed to send shutdown command: %s", err)
|
||||||
state.Put("error", err)
|
state.Put("error", err)
|
||||||
ui.Error(err.Error())
|
ui.Error(err.Error())
|
||||||
|
|
|
@ -2,6 +2,7 @@ package adapter
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
@ -233,15 +234,15 @@ func (c *Adapter) remoteExec(command string, in io.Reader, out io.Writer, err io
|
||||||
Stderr: err,
|
Stderr: err,
|
||||||
Command: command,
|
Command: command,
|
||||||
}
|
}
|
||||||
|
ctx := context.TODO()
|
||||||
|
|
||||||
if err := c.comm.Start(cmd); err != nil {
|
if err := c.comm.Start(ctx, cmd); err != nil {
|
||||||
c.ui.Error(err.Error())
|
c.ui.Error(err.Error())
|
||||||
return cmd.ExitStatus
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.Wait()
|
cmd.Wait()
|
||||||
|
|
||||||
return cmd.ExitStatus
|
return cmd.ExitStatus()
|
||||||
}
|
}
|
||||||
|
|
||||||
type envRequest struct {
|
type envRequest struct {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package adapter
|
package adapter
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
|
@ -95,7 +96,7 @@ func (a addr) String() string {
|
||||||
|
|
||||||
type communicator struct{}
|
type communicator struct{}
|
||||||
|
|
||||||
func (c communicator) Start(*packer.RemoteCmd) error {
|
func (c communicator) Start(context.Context, *packer.RemoteCmd) error {
|
||||||
return errors.New("communicator not supported")
|
return errors.New("communicator not supported")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package shell_local
|
package shell_local
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
|
@ -15,14 +16,14 @@ type Communicator struct {
|
||||||
ExecuteCommand []string
|
ExecuteCommand []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Communicator) Start(cmd *packer.RemoteCmd) error {
|
func (c *Communicator) Start(ctx context.Context, cmd *packer.RemoteCmd) error {
|
||||||
if len(c.ExecuteCommand) == 0 {
|
if len(c.ExecuteCommand) == 0 {
|
||||||
return fmt.Errorf("Error launching command via shell-local communicator: No ExecuteCommand provided")
|
return fmt.Errorf("Error launching command via shell-local communicator: No ExecuteCommand provided")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build the local command to execute
|
// Build the local command to execute
|
||||||
log.Printf("[INFO] (shell-local communicator): Executing local shell command %s", c.ExecuteCommand)
|
log.Printf("[INFO] (shell-local communicator): Executing local shell command %s", c.ExecuteCommand)
|
||||||
localCmd := exec.Command(c.ExecuteCommand[0], c.ExecuteCommand[1:]...)
|
localCmd := exec.CommandContext(ctx, c.ExecuteCommand[0], c.ExecuteCommand[1:]...)
|
||||||
localCmd.Stdin = cmd.Stdin
|
localCmd.Stdin = cmd.Stdin
|
||||||
localCmd.Stdout = cmd.Stdout
|
localCmd.Stdout = cmd.Stdout
|
||||||
localCmd.Stderr = cmd.Stderr
|
localCmd.Stderr = cmd.Stderr
|
||||||
|
|
|
@ -2,6 +2,7 @@ package shell_local
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -28,14 +29,15 @@ func TestCommunicator(t *testing.T) {
|
||||||
Stdout: &buf,
|
Stdout: &buf,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.Start(cmd); err != nil {
|
ctx := context.Background()
|
||||||
|
if err := c.Start(ctx, cmd); err != nil {
|
||||||
t.Fatalf("err: %s", err)
|
t.Fatalf("err: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.Wait()
|
cmd.Wait()
|
||||||
|
|
||||||
if cmd.ExitStatus != 0 {
|
if cmd.ExitStatus() != 0 {
|
||||||
t.Fatalf("err bad exit status: %d", cmd.ExitStatus)
|
t.Fatalf("err bad exit status: %d", cmd.ExitStatus())
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.TrimSpace(buf.String()) != "foo" {
|
if strings.TrimSpace(buf.String()) != "foo" {
|
||||||
|
|
|
@ -2,6 +2,7 @@ package shell_local
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
@ -27,7 +28,7 @@ type EnvVarsTemplate struct {
|
||||||
WinRMPassword string
|
WinRMPassword string
|
||||||
}
|
}
|
||||||
|
|
||||||
func Run(ui packer.Ui, config *Config) (bool, error) {
|
func Run(ctx context.Context, ui packer.Ui, config *Config) (bool, error) {
|
||||||
// Check if shell-local can even execute against this runtime OS
|
// Check if shell-local can even execute against this runtime OS
|
||||||
if len(config.OnlyOn) > 0 {
|
if len(config.OnlyOn) > 0 {
|
||||||
runCommand := false
|
runCommand := false
|
||||||
|
@ -90,17 +91,17 @@ func Run(ui packer.Ui, config *Config) (bool, error) {
|
||||||
flattenedCmd := strings.Join(interpolatedCmds, " ")
|
flattenedCmd := strings.Join(interpolatedCmds, " ")
|
||||||
cmd := &packer.RemoteCmd{Command: flattenedCmd}
|
cmd := &packer.RemoteCmd{Command: flattenedCmd}
|
||||||
log.Printf("[INFO] (shell-local): starting local command: %s", flattenedCmd)
|
log.Printf("[INFO] (shell-local): starting local command: %s", flattenedCmd)
|
||||||
if err := cmd.StartWithUi(comm, ui); err != nil {
|
if err := cmd.RunWithUi(ctx, comm, ui); err != nil {
|
||||||
return false, fmt.Errorf(
|
return false, fmt.Errorf(
|
||||||
"Error executing script: %s\n\n"+
|
"Error executing script: %s\n\n"+
|
||||||
"Please see output above for more information.",
|
"Please see output above for more information.",
|
||||||
script)
|
script)
|
||||||
}
|
}
|
||||||
if cmd.ExitStatus != 0 {
|
if cmd.ExitStatus() != 0 {
|
||||||
return false, fmt.Errorf(
|
return false, fmt.Errorf(
|
||||||
"Erroneous exit code %d while executing script: %s\n\n"+
|
"Erroneous exit code %d while executing script: %s\n\n"+
|
||||||
"Please see output above for more information.",
|
"Please see output above for more information.",
|
||||||
cmd.ExitStatus,
|
cmd.ExitStatus(),
|
||||||
script)
|
script)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,12 +56,12 @@ func (s *StepCleanupTempKeys) Run(ctx context.Context, state multistep.StateBag)
|
||||||
//
|
//
|
||||||
// TODO: Why create a backup file if you are going to remove it?
|
// TODO: Why create a backup file if you are going to remove it?
|
||||||
cmd.Command = fmt.Sprintf("sed -i.bak '/ %s$/d' ~/.ssh/authorized_keys; rm ~/.ssh/authorized_keys.bak", s.Comm.SSHTemporaryKeyPairName)
|
cmd.Command = fmt.Sprintf("sed -i.bak '/ %s$/d' ~/.ssh/authorized_keys; rm ~/.ssh/authorized_keys.bak", s.Comm.SSHTemporaryKeyPairName)
|
||||||
if err := cmd.StartWithUi(comm, ui); err != nil {
|
if err := cmd.RunWithUi(ctx, comm, ui); err != nil {
|
||||||
log.Printf("Error cleaning up ~/.ssh/authorized_keys; please clean up keys manually: %s", err)
|
log.Printf("Error cleaning up ~/.ssh/authorized_keys; please clean up keys manually: %s", err)
|
||||||
}
|
}
|
||||||
cmd = new(packer.RemoteCmd)
|
cmd = new(packer.RemoteCmd)
|
||||||
cmd.Command = fmt.Sprintf("sudo sed -i.bak '/ %s$/d' /root/.ssh/authorized_keys; sudo rm /root/.ssh/authorized_keys.bak", s.Comm.SSHTemporaryKeyPairName)
|
cmd.Command = fmt.Sprintf("sudo sed -i.bak '/ %s$/d' /root/.ssh/authorized_keys; sudo rm /root/.ssh/authorized_keys.bak", s.Comm.SSHTemporaryKeyPairName)
|
||||||
if err := cmd.StartWithUi(comm, ui); err != nil {
|
if err := cmd.RunWithUi(ctx, comm, ui); err != nil {
|
||||||
log.Printf("Error cleaning up /root/.ssh/authorized_keys; please clean up keys manually: %s", err)
|
log.Printf("Error cleaning up /root/.ssh/authorized_keys; please clean up keys manually: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package none
|
package none
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
@ -23,7 +24,7 @@ func New(config string) (result *comm, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *comm) Start(cmd *packer.RemoteCmd) (err error) {
|
func (c *comm) Start(ctx context.Context, cmd *packer.RemoteCmd) (err error) {
|
||||||
cmd.SetExited(0)
|
cmd.SetExited(0)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package ssh
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
@ -82,7 +83,7 @@ func New(address string, config *Config) (result *comm, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *comm) Start(cmd *packer.RemoteCmd) (err error) {
|
func (c *comm) Start(ctx context.Context, cmd *packer.RemoteCmd) (err error) {
|
||||||
session, err := c.newSession()
|
session, err := c.newSession()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
|
|
@ -4,6 +4,7 @@ package ssh
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -188,7 +189,8 @@ func TestStart(t *testing.T) {
|
||||||
Stdout: new(bytes.Buffer),
|
Stdout: new(bytes.Buffer),
|
||||||
}
|
}
|
||||||
|
|
||||||
client.Start(cmd)
|
ctx := context.Background()
|
||||||
|
client.Start(ctx, cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHandshakeTimeout(t *testing.T) {
|
func TestHandshakeTimeout(t *testing.T) {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package winrm
|
package winrm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
@ -74,7 +75,7 @@ func New(config *Config) (*Communicator, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start implementation of communicator.Communicator interface
|
// Start implementation of communicator.Communicator interface
|
||||||
func (c *Communicator) Start(rc *packer.RemoteCmd) error {
|
func (c *Communicator) Start(ctx context.Context, rc *packer.RemoteCmd) error {
|
||||||
shell, err := c.client.CreateShell()
|
shell, err := c.client.CreateShell()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -2,6 +2,7 @@ package winrm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"io"
|
"io"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -77,8 +78,8 @@ func TestStart(t *testing.T) {
|
||||||
stdout := new(bytes.Buffer)
|
stdout := new(bytes.Buffer)
|
||||||
cmd.Command = "echo foo"
|
cmd.Command = "echo foo"
|
||||||
cmd.Stdout = stdout
|
cmd.Stdout = stdout
|
||||||
|
ctx := context.Background()
|
||||||
err = c.Start(&cmd)
|
err = c.Start(ctx, &cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error executing remote command: %s", err)
|
t.Fatalf("error executing remote command: %s", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ type StepConnectWinRM struct {
|
||||||
WinRMPort func(multistep.StateBag) (int, error)
|
WinRMPort func(multistep.StateBag) (int, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *StepConnectWinRM) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
func (s *StepConnectWinRM) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
|
||||||
ui := state.Get("ui").(packer.Ui)
|
ui := state.Get("ui").(packer.Ui)
|
||||||
|
|
||||||
var comm packer.Communicator
|
var comm packer.Communicator
|
||||||
|
@ -87,6 +87,7 @@ func (s *StepConnectWinRM) Cleanup(multistep.StateBag) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *StepConnectWinRM) waitForWinRM(state multistep.StateBag, cancel <-chan struct{}) (packer.Communicator, error) {
|
func (s *StepConnectWinRM) waitForWinRM(state multistep.StateBag, cancel <-chan struct{}) (packer.Communicator, error) {
|
||||||
|
ctx := context.TODO()
|
||||||
var comm packer.Communicator
|
var comm packer.Communicator
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
|
@ -164,7 +165,7 @@ func (s *StepConnectWinRM) waitForWinRM(state multistep.StateBag, cancel <-chan
|
||||||
|
|
||||||
log.Printf("Checking that WinRM is connected with: '%s'", connectCheckCommand)
|
log.Printf("Checking that WinRM is connected with: '%s'", connectCheckCommand)
|
||||||
ui := state.Get("ui").(packer.Ui)
|
ui := state.Get("ui").(packer.Ui)
|
||||||
err := cmd.StartWithUi(comm, ui)
|
err := cmd.RunWithUi(ctx, comm, ui)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Communication connection err: %s", err)
|
log.Printf("Communication connection err: %s", err)
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
package packer
|
package packer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"unicode"
|
"unicode"
|
||||||
|
|
||||||
|
"golang.org/x/sync/errgroup"
|
||||||
|
|
||||||
"github.com/mitchellh/iochan"
|
"github.com/mitchellh/iochan"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -32,19 +35,14 @@ type RemoteCmd struct {
|
||||||
Stdout io.Writer
|
Stdout io.Writer
|
||||||
Stderr io.Writer
|
Stderr io.Writer
|
||||||
|
|
||||||
// This will be set to true when the remote command has exited. It
|
|
||||||
// shouldn't be set manually by the user, but there is no harm in
|
|
||||||
// doing so.
|
|
||||||
Exited bool
|
|
||||||
|
|
||||||
// Once Exited is true, this will contain the exit code of the process.
|
// Once Exited is true, this will contain the exit code of the process.
|
||||||
ExitStatus int
|
exitStatus int
|
||||||
|
|
||||||
// Internal fields
|
|
||||||
exitCh chan struct{}
|
|
||||||
|
|
||||||
// This thing is a mutex, lock when making modifications concurrently
|
// This thing is a mutex, lock when making modifications concurrently
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
|
|
||||||
|
exitChInit sync.Once
|
||||||
|
exitCh chan interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// A Communicator is the interface used to communicate with the machine
|
// A Communicator is the interface used to communicate with the machine
|
||||||
|
@ -59,7 +57,7 @@ type Communicator interface {
|
||||||
// Start again. The Start method returns immediately once the command
|
// Start again. The Start method returns immediately once the command
|
||||||
// is started. It does not wait for the command to complete. The
|
// is started. It does not wait for the command to complete. The
|
||||||
// RemoteCmd.Exited field should be used for this.
|
// RemoteCmd.Exited field should be used for this.
|
||||||
Start(*RemoteCmd) error
|
Start(context.Context, *RemoteCmd) error
|
||||||
|
|
||||||
// Upload uploads a file to the machine to the given path with the
|
// Upload uploads a file to the machine to the given path with the
|
||||||
// contents coming from the given reader. This method will block until
|
// contents coming from the given reader. This method will block until
|
||||||
|
@ -84,10 +82,12 @@ type Communicator interface {
|
||||||
DownloadDir(src string, dst string, exclude []string) error
|
DownloadDir(src string, dst string, exclude []string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// StartWithUi runs the remote command and streams the output to any
|
// RunWithUi runs the remote command and streams the output to any configured
|
||||||
// configured Writers for stdout/stderr, while also writing each line
|
// Writers for stdout/stderr, while also writing each line as it comes to a Ui.
|
||||||
// as it comes to a Ui.
|
// RunWithUi will not return until the command finishes or is cancelled.
|
||||||
func (r *RemoteCmd) StartWithUi(c Communicator, ui Ui) error {
|
func (r *RemoteCmd) RunWithUi(ctx context.Context, c Communicator, ui Ui) error {
|
||||||
|
r.initchan()
|
||||||
|
|
||||||
stdout_r, stdout_w := io.Pipe()
|
stdout_r, stdout_w := io.Pipe()
|
||||||
stderr_r, stderr_w := io.Pipe()
|
stderr_r, stderr_w := io.Pipe()
|
||||||
defer stdout_w.Close()
|
defer stdout_w.Close()
|
||||||
|
@ -117,85 +117,69 @@ func (r *RemoteCmd) StartWithUi(c Communicator, ui Ui) error {
|
||||||
r.Stderr = io.MultiWriter(r.Stderr, stderr_w)
|
r.Stderr = io.MultiWriter(r.Stderr, stderr_w)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start the command
|
// Loop and get all our output until done.
|
||||||
if err := c.Start(r); err != nil {
|
printFn := func(in io.Reader, out func(string)) error {
|
||||||
|
for output := range iochan.DelimReader(in, '\n') {
|
||||||
|
if output != "" {
|
||||||
|
out(cleanOutputLine(output))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
wg, ctx := errgroup.WithContext(ctx)
|
||||||
|
|
||||||
|
wg.Go(func() error { return printFn(stdout_r, ui.Message) })
|
||||||
|
wg.Go(func() error { return printFn(stderr_r, ui.Error) })
|
||||||
|
|
||||||
|
if err := c.Start(ctx, r); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the channels we'll use for data
|
|
||||||
exitCh := make(chan struct{})
|
|
||||||
stdoutCh := iochan.DelimReader(stdout_r, '\n')
|
|
||||||
stderrCh := iochan.DelimReader(stderr_r, '\n')
|
|
||||||
|
|
||||||
// Start the goroutine to watch for the exit
|
|
||||||
go func() {
|
|
||||||
defer close(exitCh)
|
|
||||||
defer stdout_w.Close()
|
|
||||||
defer stderr_w.Close()
|
|
||||||
r.Wait()
|
|
||||||
}()
|
|
||||||
|
|
||||||
// Loop and get all our output
|
|
||||||
OutputLoop:
|
|
||||||
for {
|
|
||||||
select {
|
select {
|
||||||
case output := <-stderrCh:
|
case <-ctx.Done():
|
||||||
if output != "" {
|
return ctx.Err()
|
||||||
ui.Message(r.cleanOutputLine(output))
|
case <-r.exitCh:
|
||||||
}
|
|
||||||
case output := <-stdoutCh:
|
|
||||||
if output != "" {
|
|
||||||
ui.Message(r.cleanOutputLine(output))
|
|
||||||
}
|
|
||||||
case <-exitCh:
|
|
||||||
break OutputLoop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure we finish off stdout/stderr because we may have gotten
|
|
||||||
// a message from the exit channel before finishing these first.
|
|
||||||
for output := range stdoutCh {
|
|
||||||
ui.Message(r.cleanOutputLine(output))
|
|
||||||
}
|
|
||||||
|
|
||||||
for output := range stderrCh {
|
|
||||||
ui.Message(r.cleanOutputLine(output))
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// SetExited is a helper for setting that this process is exited. This
|
// SetExited is a helper for setting that this process is exited. This
|
||||||
// should be called by communicators who are running a remote command in
|
// should be called by communicators who are running a remote command in
|
||||||
// order to set that the command is done.
|
// order to set that the command is done.
|
||||||
func (r *RemoteCmd) SetExited(status int) {
|
func (r *RemoteCmd) SetExited(status int) {
|
||||||
|
r.initchan()
|
||||||
|
|
||||||
r.Lock()
|
r.Lock()
|
||||||
defer r.Unlock()
|
r.exitStatus = status
|
||||||
|
r.Unlock()
|
||||||
|
|
||||||
if r.exitCh == nil {
|
|
||||||
r.exitCh = make(chan struct{})
|
|
||||||
}
|
|
||||||
|
|
||||||
r.Exited = true
|
|
||||||
r.ExitStatus = status
|
|
||||||
close(r.exitCh)
|
close(r.exitCh)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait waits for the remote command to complete.
|
// Wait for command exit and return exit status
|
||||||
func (r *RemoteCmd) Wait() {
|
func (r *RemoteCmd) Wait() int {
|
||||||
// Make sure our condition variable is initialized.
|
r.initchan()
|
||||||
r.Lock()
|
|
||||||
if r.exitCh == nil {
|
|
||||||
r.exitCh = make(chan struct{})
|
|
||||||
}
|
|
||||||
r.Unlock()
|
|
||||||
|
|
||||||
<-r.exitCh
|
<-r.exitCh
|
||||||
|
r.Lock()
|
||||||
|
defer r.Unlock()
|
||||||
|
return r.exitStatus
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RemoteCmd) ExitStatus() int {
|
||||||
|
return r.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RemoteCmd) initchan() {
|
||||||
|
r.exitChInit.Do(func() {
|
||||||
|
if r.exitCh == nil {
|
||||||
|
r.exitCh = make(chan interface{})
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// cleanOutputLine cleans up a line so that '\r' don't muck up the
|
// cleanOutputLine cleans up a line so that '\r' don't muck up the
|
||||||
// UI output when we're reading from a remote command.
|
// UI output when we're reading from a remote command.
|
||||||
func (r *RemoteCmd) cleanOutputLine(line string) string {
|
func cleanOutputLine(line string) string {
|
||||||
// Trim surrounding whitespace
|
// Trim surrounding whitespace
|
||||||
line = strings.TrimRightFunc(line, unicode.IsSpace)
|
line = strings.TrimRightFunc(line, unicode.IsSpace)
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ package packer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
|
@ -34,7 +35,7 @@ type MockCommunicator struct {
|
||||||
DownloadData string
|
DownloadData string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *MockCommunicator) Start(rc *RemoteCmd) error {
|
func (c *MockCommunicator) Start(ctx context.Context, rc *RemoteCmd) error {
|
||||||
c.StartCalled = true
|
c.StartCalled = true
|
||||||
c.StartCmd = rc
|
c.StartCmd = rc
|
||||||
|
|
||||||
|
|
|
@ -2,9 +2,12 @@ package packer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/go-cmp/cmp"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestRemoteCmd_StartWithUi(t *testing.T) {
|
func TestRemoteCmd_StartWithUi(t *testing.T) {
|
||||||
|
@ -24,17 +27,19 @@ func TestRemoteCmd_StartWithUi(t *testing.T) {
|
||||||
Command: "test",
|
Command: "test",
|
||||||
Stdout: originalOutput,
|
Stdout: originalOutput,
|
||||||
}
|
}
|
||||||
|
ctx := context.TODO()
|
||||||
|
|
||||||
err := rc.StartWithUi(testComm, testUi)
|
err := rc.RunWithUi(ctx, testComm, testUi)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %s", err)
|
t.Fatalf("err: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
rc.Wait()
|
// sometimes cmd has returned and everything can be printed later on
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
|
||||||
expected := strings.TrimSpace(data)
|
expected := strings.TrimSpace(data)
|
||||||
if strings.TrimSpace(uiOutput.String()) != expected {
|
if diff := cmp.Diff(strings.TrimSpace(uiOutput.String()), expected); diff != "" {
|
||||||
t.Fatalf("bad output: '%s'", uiOutput.String())
|
t.Fatalf("bad output: %s", diff)
|
||||||
}
|
}
|
||||||
|
|
||||||
if originalOutput.String() != expected {
|
if originalOutput.String() != expected {
|
||||||
|
|
|
@ -16,10 +16,10 @@ const HookProvision = "packer_provision"
|
||||||
// in. In addition to that, the Hook is given access to a UI so that it can
|
// in. In addition to that, the Hook is given access to a UI so that it can
|
||||||
// output things to the user.
|
// output things to the user.
|
||||||
//
|
//
|
||||||
// Cancel is called when the hook needs to be cancelled. This will usually
|
// The first context argument controlls cancellation, the context will usually
|
||||||
// be called when Run is still in progress so the mechanism that handles this
|
// be called when Run is still in progress so the mechanism that handles this
|
||||||
// must be race-free. Cancel should attempt to cancel the hook in the
|
// must be race-free. Cancel should attempt to cancel the hook in the quickest,
|
||||||
// quickest, safest way possible.
|
// safest way possible.
|
||||||
type Hook interface {
|
type Hook interface {
|
||||||
Run(context.Context, string, Ui, Communicator, interface{}) error
|
Run(context.Context, string, Ui, Communicator, interface{}) error
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package rpc
|
package rpc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/gob"
|
"encoding/gob"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
|
@ -64,7 +65,7 @@ func Communicator(client *rpc.Client) *communicator {
|
||||||
return &communicator{client: client}
|
return &communicator{client: client}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *communicator) Start(cmd *packer.RemoteCmd) (err error) {
|
func (c *communicator) Start(ctx context.Context, cmd *packer.RemoteCmd) (err error) {
|
||||||
var args CommunicatorStartArgs
|
var args CommunicatorStartArgs
|
||||||
args.Command = cmd.Command
|
args.Command = cmd.Command
|
||||||
|
|
||||||
|
@ -201,6 +202,8 @@ func (c *communicator) Download(path string, w io.Writer) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CommunicatorServer) Start(args *CommunicatorStartArgs, reply *interface{}) error {
|
func (c *CommunicatorServer) Start(args *CommunicatorStartArgs, reply *interface{}) error {
|
||||||
|
ctx := context.TODO()
|
||||||
|
|
||||||
// Build the RemoteCmd on this side so that it all pipes over
|
// Build the RemoteCmd on this side so that it all pipes over
|
||||||
// to the remote side.
|
// to the remote side.
|
||||||
var cmd packer.RemoteCmd
|
var cmd packer.RemoteCmd
|
||||||
|
@ -260,7 +263,7 @@ func (c *CommunicatorServer) Start(args *CommunicatorStartArgs, reply *interface
|
||||||
responseWriter := gob.NewEncoder(responseC)
|
responseWriter := gob.NewEncoder(responseC)
|
||||||
|
|
||||||
// Start the actual command
|
// Start the actual command
|
||||||
err = c.c.Start(&cmd)
|
err = c.c.Start(ctx, &cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
close(doneCh)
|
close(doneCh)
|
||||||
return NewBasicError(err)
|
return NewBasicError(err)
|
||||||
|
@ -272,8 +275,8 @@ func (c *CommunicatorServer) Start(args *CommunicatorStartArgs, reply *interface
|
||||||
defer close(doneCh)
|
defer close(doneCh)
|
||||||
defer responseC.Close()
|
defer responseC.Close()
|
||||||
cmd.Wait()
|
cmd.Wait()
|
||||||
log.Printf("[INFO] RPC endpoint: Communicator ended with: %d", cmd.ExitStatus)
|
log.Printf("[INFO] RPC endpoint: Communicator ended with: %d", cmd.ExitStatus())
|
||||||
responseWriter.Encode(&CommandFinished{cmd.ExitStatus})
|
responseWriter.Encode(&CommandFinished{cmd.ExitStatus()})
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -2,6 +2,7 @@ package rpc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"context"
|
||||||
"io"
|
"io"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -36,8 +37,10 @@ func TestCommunicatorRPC(t *testing.T) {
|
||||||
c.StartStderr = "errfoo\n"
|
c.StartStderr = "errfoo\n"
|
||||||
c.StartExitStatus = 42
|
c.StartExitStatus = 42
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
// Test Start
|
// Test Start
|
||||||
err := remote.Start(&cmd)
|
err := remote.Start(ctx, &cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %s", err)
|
t.Fatalf("err: %s", err)
|
||||||
}
|
}
|
||||||
|
@ -73,8 +76,8 @@ func TestCommunicatorRPC(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test that we can get the exit status properly
|
// Test that we can get the exit status properly
|
||||||
if cmd.ExitStatus != 42 {
|
if cmd.ExitStatus() != 42 {
|
||||||
t.Fatalf("bad exit: %d", cmd.ExitStatus)
|
t.Fatalf("bad exit: %d", cmd.ExitStatus())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test that we can upload things
|
// Test that we can upload things
|
||||||
|
|
|
@ -41,7 +41,7 @@ func (p *PostProcessor) PostProcess(ctx context.Context, ui packer.Ui, artifact
|
||||||
// this particular post-processor doesn't do anything with the artifact
|
// this particular post-processor doesn't do anything with the artifact
|
||||||
// except to return it.
|
// except to return it.
|
||||||
|
|
||||||
success, retErr := sl.Run(ui, &p.config)
|
success, retErr := sl.Run(ctx, ui, &p.config)
|
||||||
if !success {
|
if !success {
|
||||||
return nil, false, false, retErr
|
return nil, false, false, retErr
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package ansiblelocal
|
package ansiblelocal
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
@ -12,7 +13,7 @@ type communicatorMock struct {
|
||||||
uploadDestination []string
|
uploadDestination []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *communicatorMock) Start(cmd *packer.RemoteCmd) error {
|
func (c *communicatorMock) Start(ctx context.Context, cmd *packer.RemoteCmd) error {
|
||||||
c.startCommand = append(c.startCommand, cmd.Command)
|
c.startCommand = append(c.startCommand, cmd.Command)
|
||||||
cmd.SetExited(0)
|
cmd.SetExited(0)
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -348,6 +348,7 @@ func (p *Provisioner) provisionPlaybookFile(ui packer.Ui, comm packer.Communicat
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provisioner) executeGalaxy(ui packer.Ui, comm packer.Communicator) error {
|
func (p *Provisioner) executeGalaxy(ui packer.Ui, comm packer.Communicator) error {
|
||||||
|
ctx := context.TODO()
|
||||||
rolesDir := filepath.ToSlash(filepath.Join(p.config.StagingDir, "roles"))
|
rolesDir := filepath.ToSlash(filepath.Join(p.config.StagingDir, "roles"))
|
||||||
galaxyFile := filepath.ToSlash(filepath.Join(p.config.StagingDir, filepath.Base(p.config.GalaxyFile)))
|
galaxyFile := filepath.ToSlash(filepath.Join(p.config.StagingDir, filepath.Base(p.config.GalaxyFile)))
|
||||||
|
|
||||||
|
@ -358,12 +359,12 @@ func (p *Provisioner) executeGalaxy(ui packer.Ui, comm packer.Communicator) erro
|
||||||
cmd := &packer.RemoteCmd{
|
cmd := &packer.RemoteCmd{
|
||||||
Command: command,
|
Command: command,
|
||||||
}
|
}
|
||||||
if err := cmd.StartWithUi(comm, ui); err != nil {
|
if err := cmd.RunWithUi(ctx, comm, ui); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if cmd.ExitStatus != 0 {
|
if cmd.ExitStatus() != 0 {
|
||||||
// ansible-galaxy version 2.0.0.2 doesn't return exit codes on error..
|
// ansible-galaxy version 2.0.0.2 doesn't return exit codes on error..
|
||||||
return fmt.Errorf("Non-zero exit status: %d", cmd.ExitStatus)
|
return fmt.Errorf("Non-zero exit status: %d", cmd.ExitStatus())
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -403,6 +404,7 @@ func (p *Provisioner) executeAnsible(ui packer.Ui, comm packer.Communicator) err
|
||||||
func (p *Provisioner) executeAnsiblePlaybook(
|
func (p *Provisioner) executeAnsiblePlaybook(
|
||||||
ui packer.Ui, comm packer.Communicator, playbookFile, extraArgs, inventory string,
|
ui packer.Ui, comm packer.Communicator, playbookFile, extraArgs, inventory string,
|
||||||
) error {
|
) error {
|
||||||
|
ctx := context.TODO()
|
||||||
command := fmt.Sprintf("cd %s && %s %s%s -c local -i %s",
|
command := fmt.Sprintf("cd %s && %s %s%s -c local -i %s",
|
||||||
p.config.StagingDir, p.config.Command, playbookFile, extraArgs, inventory,
|
p.config.StagingDir, p.config.Command, playbookFile, extraArgs, inventory,
|
||||||
)
|
)
|
||||||
|
@ -410,17 +412,17 @@ func (p *Provisioner) executeAnsiblePlaybook(
|
||||||
cmd := &packer.RemoteCmd{
|
cmd := &packer.RemoteCmd{
|
||||||
Command: command,
|
Command: command,
|
||||||
}
|
}
|
||||||
if err := cmd.StartWithUi(comm, ui); err != nil {
|
if err := cmd.RunWithUi(ctx, comm, ui); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if cmd.ExitStatus != 0 {
|
if cmd.ExitStatus() != 0 {
|
||||||
if cmd.ExitStatus == 127 {
|
if cmd.ExitStatus() == 127 {
|
||||||
return fmt.Errorf("%s could not be found. Verify that it is available on the\n"+
|
return fmt.Errorf("%s could not be found. Verify that it is available on the\n"+
|
||||||
"PATH after connecting to the machine.",
|
"PATH after connecting to the machine.",
|
||||||
p.config.Command)
|
p.config.Command)
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Errorf("Non-zero exit status: %d", cmd.ExitStatus)
|
return fmt.Errorf("Non-zero exit status: %d", cmd.ExitStatus())
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -464,32 +466,34 @@ func (p *Provisioner) uploadFile(ui packer.Ui, comm packer.Communicator, dst, sr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provisioner) createDir(ui packer.Ui, comm packer.Communicator, dir string) error {
|
func (p *Provisioner) createDir(ui packer.Ui, comm packer.Communicator, dir string) error {
|
||||||
|
ctx := context.TODO()
|
||||||
cmd := &packer.RemoteCmd{
|
cmd := &packer.RemoteCmd{
|
||||||
Command: fmt.Sprintf("mkdir -p '%s'", dir),
|
Command: fmt.Sprintf("mkdir -p '%s'", dir),
|
||||||
}
|
}
|
||||||
|
|
||||||
ui.Message(fmt.Sprintf("Creating directory: %s", dir))
|
ui.Message(fmt.Sprintf("Creating directory: %s", dir))
|
||||||
if err := cmd.StartWithUi(comm, ui); err != nil {
|
if err := cmd.RunWithUi(ctx, comm, ui); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if cmd.ExitStatus != 0 {
|
if cmd.ExitStatus() != 0 {
|
||||||
return fmt.Errorf("Non-zero exit status. See output above for more information.")
|
return fmt.Errorf("Non-zero exit status. See output above for more information.")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provisioner) removeDir(ui packer.Ui, comm packer.Communicator, dir string) error {
|
func (p *Provisioner) removeDir(ui packer.Ui, comm packer.Communicator, dir string) error {
|
||||||
|
ctx := context.TODO()
|
||||||
cmd := &packer.RemoteCmd{
|
cmd := &packer.RemoteCmd{
|
||||||
Command: fmt.Sprintf("rm -rf '%s'", dir),
|
Command: fmt.Sprintf("rm -rf '%s'", dir),
|
||||||
}
|
}
|
||||||
|
|
||||||
ui.Message(fmt.Sprintf("Removing directory: %s", dir))
|
ui.Message(fmt.Sprintf("Removing directory: %s", dir))
|
||||||
if err := cmd.StartWithUi(comm, ui); err != nil {
|
if err := cmd.RunWithUi(ctx, comm, ui); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if cmd.ExitStatus != 0 {
|
if cmd.ExitStatus() != 0 {
|
||||||
return fmt.Errorf("Non-zero exit status. See output above for more information.")
|
return fmt.Errorf("Non-zero exit status. See output above for more information.")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -467,22 +467,23 @@ func (p *Provisioner) createJson(ui packer.Ui, comm packer.Communicator) (string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provisioner) createDir(ui packer.Ui, comm packer.Communicator, dir string) error {
|
func (p *Provisioner) createDir(ui packer.Ui, comm packer.Communicator, dir string) error {
|
||||||
|
ctx := context.TODO()
|
||||||
ui.Message(fmt.Sprintf("Creating directory: %s", dir))
|
ui.Message(fmt.Sprintf("Creating directory: %s", dir))
|
||||||
|
|
||||||
cmd := &packer.RemoteCmd{Command: p.guestCommands.CreateDir(dir)}
|
cmd := &packer.RemoteCmd{Command: p.guestCommands.CreateDir(dir)}
|
||||||
if err := cmd.StartWithUi(comm, ui); err != nil {
|
if err := cmd.RunWithUi(ctx, comm, ui); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if cmd.ExitStatus != 0 {
|
if cmd.ExitStatus() != 0 {
|
||||||
return fmt.Errorf("Non-zero exit status. See output above for more info.")
|
return fmt.Errorf("Non-zero exit status. See output above for more info.")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Chmod the directory to 0777 just so that we can access it as our user
|
// Chmod the directory to 0777 just so that we can access it as our user
|
||||||
cmd = &packer.RemoteCmd{Command: p.guestCommands.Chmod(dir, "0777")}
|
cmd = &packer.RemoteCmd{Command: p.guestCommands.Chmod(dir, "0777")}
|
||||||
if err := cmd.StartWithUi(comm, ui); err != nil {
|
if err := cmd.RunWithUi(ctx, comm, ui); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if cmd.ExitStatus != 0 {
|
if cmd.ExitStatus() != 0 {
|
||||||
return fmt.Errorf("Non-zero exit status. See output above for more info.")
|
return fmt.Errorf("Non-zero exit status. See output above for more info.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -514,6 +515,7 @@ func (p *Provisioner) knifeExec(ui packer.Ui, comm packer.Communicator, node str
|
||||||
"-y",
|
"-y",
|
||||||
"-c", knifeConfigPath,
|
"-c", knifeConfigPath,
|
||||||
}
|
}
|
||||||
|
ctx := context.TODO()
|
||||||
|
|
||||||
p.config.ctx.Data = &KnifeTemplate{
|
p.config.ctx.Data = &KnifeTemplate{
|
||||||
Sudo: !p.config.PreventSudo,
|
Sudo: !p.config.PreventSudo,
|
||||||
|
@ -527,10 +529,10 @@ func (p *Provisioner) knifeExec(ui packer.Ui, comm packer.Communicator, node str
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := &packer.RemoteCmd{Command: command}
|
cmd := &packer.RemoteCmd{Command: command}
|
||||||
if err := cmd.StartWithUi(comm, ui); err != nil {
|
if err := cmd.RunWithUi(ctx, comm, ui); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if cmd.ExitStatus != 0 {
|
if cmd.ExitStatus() != 0 {
|
||||||
return fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"Non-zero exit status. See output above for more info.\n\n"+
|
"Non-zero exit status. See output above for more info.\n\n"+
|
||||||
"Command: %s",
|
"Command: %s",
|
||||||
|
@ -542,9 +544,10 @@ func (p *Provisioner) knifeExec(ui packer.Ui, comm packer.Communicator, node str
|
||||||
|
|
||||||
func (p *Provisioner) removeDir(ui packer.Ui, comm packer.Communicator, dir string) error {
|
func (p *Provisioner) removeDir(ui packer.Ui, comm packer.Communicator, dir string) error {
|
||||||
ui.Message(fmt.Sprintf("Removing directory: %s", dir))
|
ui.Message(fmt.Sprintf("Removing directory: %s", dir))
|
||||||
|
ctx := context.TODO()
|
||||||
|
|
||||||
cmd := &packer.RemoteCmd{Command: p.guestCommands.RemoveDir(dir)}
|
cmd := &packer.RemoteCmd{Command: p.guestCommands.RemoveDir(dir)}
|
||||||
if err := cmd.StartWithUi(comm, ui); err != nil {
|
if err := cmd.RunWithUi(ctx, comm, ui); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -557,6 +560,8 @@ func (p *Provisioner) executeChef(ui packer.Ui, comm packer.Communicator, config
|
||||||
JsonPath: json,
|
JsonPath: json,
|
||||||
Sudo: !p.config.PreventSudo,
|
Sudo: !p.config.PreventSudo,
|
||||||
}
|
}
|
||||||
|
ctx := context.TODO()
|
||||||
|
|
||||||
command, err := interpolate.Render(p.config.ExecuteCommand, &p.config.ctx)
|
command, err := interpolate.Render(p.config.ExecuteCommand, &p.config.ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -575,12 +580,12 @@ func (p *Provisioner) executeChef(ui packer.Ui, comm packer.Communicator, config
|
||||||
Command: command,
|
Command: command,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := cmd.StartWithUi(comm, ui); err != nil {
|
if err := cmd.RunWithUi(ctx, comm, ui); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if cmd.ExitStatus != 0 {
|
if cmd.ExitStatus() != 0 {
|
||||||
return fmt.Errorf("Non-zero exit status: %d", cmd.ExitStatus)
|
return fmt.Errorf("Non-zero exit status: %d", cmd.ExitStatus())
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -588,6 +593,7 @@ func (p *Provisioner) executeChef(ui packer.Ui, comm packer.Communicator, config
|
||||||
|
|
||||||
func (p *Provisioner) installChef(ui packer.Ui, comm packer.Communicator) error {
|
func (p *Provisioner) installChef(ui packer.Ui, comm packer.Communicator) error {
|
||||||
ui.Message("Installing Chef...")
|
ui.Message("Installing Chef...")
|
||||||
|
ctx := context.TODO()
|
||||||
|
|
||||||
p.config.ctx.Data = &InstallChefTemplate{
|
p.config.ctx.Data = &InstallChefTemplate{
|
||||||
Sudo: !p.config.PreventSudo,
|
Sudo: !p.config.PreventSudo,
|
||||||
|
@ -600,13 +606,13 @@ func (p *Provisioner) installChef(ui packer.Ui, comm packer.Communicator) error
|
||||||
ui.Message(command)
|
ui.Message(command)
|
||||||
|
|
||||||
cmd := &packer.RemoteCmd{Command: command}
|
cmd := &packer.RemoteCmd{Command: command}
|
||||||
if err := cmd.StartWithUi(comm, ui); err != nil {
|
if err := cmd.RunWithUi(ctx, comm, ui); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if cmd.ExitStatus != 0 {
|
if cmd.ExitStatus() != 0 {
|
||||||
return fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"Install script exited with non-zero exit status %d", cmd.ExitStatus)
|
"Install script exited with non-zero exit status %d", cmd.ExitStatus())
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -410,21 +410,22 @@ func (p *Provisioner) createJson(ui packer.Ui, comm packer.Communicator) (string
|
||||||
|
|
||||||
func (p *Provisioner) createDir(ui packer.Ui, comm packer.Communicator, dir string) error {
|
func (p *Provisioner) createDir(ui packer.Ui, comm packer.Communicator, dir string) error {
|
||||||
ui.Message(fmt.Sprintf("Creating directory: %s", dir))
|
ui.Message(fmt.Sprintf("Creating directory: %s", dir))
|
||||||
|
ctx := context.TODO()
|
||||||
|
|
||||||
cmd := &packer.RemoteCmd{Command: p.guestCommands.CreateDir(dir)}
|
cmd := &packer.RemoteCmd{Command: p.guestCommands.CreateDir(dir)}
|
||||||
if err := cmd.StartWithUi(comm, ui); err != nil {
|
if err := cmd.RunWithUi(ctx, comm, ui); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if cmd.ExitStatus != 0 {
|
if cmd.ExitStatus() != 0 {
|
||||||
return fmt.Errorf("Non-zero exit status. See output above for more info.")
|
return fmt.Errorf("Non-zero exit status. See output above for more info.")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Chmod the directory to 0777 just so that we can access it as our user
|
// Chmod the directory to 0777 just so that we can access it as our user
|
||||||
cmd = &packer.RemoteCmd{Command: p.guestCommands.Chmod(dir, "0777")}
|
cmd = &packer.RemoteCmd{Command: p.guestCommands.Chmod(dir, "0777")}
|
||||||
if err := cmd.StartWithUi(comm, ui); err != nil {
|
if err := cmd.RunWithUi(ctx, comm, ui); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if cmd.ExitStatus != 0 {
|
if cmd.ExitStatus() != 0 {
|
||||||
return fmt.Errorf("Non-zero exit status. See output above for more info.")
|
return fmt.Errorf("Non-zero exit status. See output above for more info.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -447,13 +448,13 @@ func (p *Provisioner) executeChef(ui packer.Ui, comm packer.Communicator, config
|
||||||
cmd := &packer.RemoteCmd{
|
cmd := &packer.RemoteCmd{
|
||||||
Command: command,
|
Command: command,
|
||||||
}
|
}
|
||||||
|
ctx := context.TODO()
|
||||||
if err := cmd.StartWithUi(comm, ui); err != nil {
|
if err := cmd.RunWithUi(ctx, comm, ui); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if cmd.ExitStatus != 0 {
|
if cmd.ExitStatus() != 0 {
|
||||||
return fmt.Errorf("Non-zero exit status: %d", cmd.ExitStatus)
|
return fmt.Errorf("Non-zero exit status: %d", cmd.ExitStatus())
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -461,6 +462,7 @@ func (p *Provisioner) executeChef(ui packer.Ui, comm packer.Communicator, config
|
||||||
|
|
||||||
func (p *Provisioner) installChef(ui packer.Ui, comm packer.Communicator, version string) error {
|
func (p *Provisioner) installChef(ui packer.Ui, comm packer.Communicator, version string) error {
|
||||||
ui.Message("Installing Chef...")
|
ui.Message("Installing Chef...")
|
||||||
|
ctx := context.TODO()
|
||||||
|
|
||||||
p.config.ctx.Data = &InstallChefTemplate{
|
p.config.ctx.Data = &InstallChefTemplate{
|
||||||
Sudo: !p.config.PreventSudo,
|
Sudo: !p.config.PreventSudo,
|
||||||
|
@ -472,13 +474,13 @@ func (p *Provisioner) installChef(ui packer.Ui, comm packer.Communicator, versio
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := &packer.RemoteCmd{Command: command}
|
cmd := &packer.RemoteCmd{Command: command}
|
||||||
if err := cmd.StartWithUi(comm, ui); err != nil {
|
if err := cmd.RunWithUi(ctx, comm, ui); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if cmd.ExitStatus != 0 {
|
if cmd.ExitStatus() != 0 {
|
||||||
return fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"Install script exited with non-zero exit status %d", cmd.ExitStatus)
|
"Install script exited with non-zero exit status %d", cmd.ExitStatus())
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -128,6 +128,7 @@ func (p *Provisioner) Provision(ctx context.Context, ui packer.Ui, comm packer.C
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provisioner) maybeBootstrap(ui packer.Ui, comm packer.Communicator) error {
|
func (p *Provisioner) maybeBootstrap(ui packer.Ui, comm packer.Communicator) error {
|
||||||
|
ctx := context.TODO()
|
||||||
if !p.config.Bootstrap {
|
if !p.config.Bootstrap {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -153,12 +154,12 @@ func (p *Provisioner) maybeBootstrap(ui packer.Ui, comm packer.Communicator) err
|
||||||
Stderr: &outErr,
|
Stderr: &outErr,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = comm.Start(cmd); err != nil {
|
if err = comm.Start(ctx, cmd); err != nil {
|
||||||
return fmt.Errorf("Error bootstrapping converge: %s", err)
|
return fmt.Errorf("Error bootstrapping converge: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.Wait()
|
cmd.Wait()
|
||||||
if cmd.ExitStatus != 0 {
|
if cmd.ExitStatus() != 0 {
|
||||||
ui.Error(out.String())
|
ui.Error(out.String())
|
||||||
ui.Error(outErr.String())
|
ui.Error(outErr.String())
|
||||||
return errors.New("Error bootstrapping converge")
|
return errors.New("Error bootstrapping converge")
|
||||||
|
@ -180,6 +181,7 @@ func (p *Provisioner) sendModuleDirectories(ui packer.Ui, comm packer.Communicat
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provisioner) applyModules(ui packer.Ui, comm packer.Communicator) error {
|
func (p *Provisioner) applyModules(ui packer.Ui, comm packer.Communicator) error {
|
||||||
|
ctx := context.TODO()
|
||||||
// create params JSON file
|
// create params JSON file
|
||||||
params, err := json.Marshal(p.config.Params)
|
params, err := json.Marshal(p.config.Params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -208,12 +210,12 @@ func (p *Provisioner) applyModules(ui packer.Ui, comm packer.Communicator) error
|
||||||
Stdout: &runOut,
|
Stdout: &runOut,
|
||||||
Stderr: &runErr,
|
Stderr: &runErr,
|
||||||
}
|
}
|
||||||
if err := comm.Start(cmd); err != nil {
|
if err := comm.Start(ctx, cmd); err != nil {
|
||||||
return fmt.Errorf("Error applying %q: %s", p.config.Module, err)
|
return fmt.Errorf("Error applying %q: %s", p.config.Module, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.Wait()
|
cmd.Wait()
|
||||||
if cmd.ExitStatus == 127 {
|
if cmd.ExitStatus() == 127 {
|
||||||
ui.Error("Could not find Converge. Is it installed and in PATH?")
|
ui.Error("Could not find Converge. Is it installed and in PATH?")
|
||||||
if !p.config.Bootstrap {
|
if !p.config.Bootstrap {
|
||||||
ui.Error("Bootstrapping was disabled for this run. That might be why Converge isn't present.")
|
ui.Error("Bootstrapping was disabled for this run. That might be why Converge isn't present.")
|
||||||
|
@ -221,10 +223,10 @@ func (p *Provisioner) applyModules(ui packer.Ui, comm packer.Communicator) error
|
||||||
|
|
||||||
return errors.New("Could not find Converge")
|
return errors.New("Could not find Converge")
|
||||||
|
|
||||||
} else if cmd.ExitStatus != 0 {
|
} else if cmd.ExitStatus() != 0 {
|
||||||
ui.Error(strings.TrimSpace(runOut.String()))
|
ui.Error(strings.TrimSpace(runOut.String()))
|
||||||
ui.Error(strings.TrimSpace(runErr.String()))
|
ui.Error(strings.TrimSpace(runErr.String()))
|
||||||
ui.Error(fmt.Sprintf("Exited with error code %d.", cmd.ExitStatus))
|
ui.Error(fmt.Sprintf("Exited with error code %d.", cmd.ExitStatus()))
|
||||||
return fmt.Errorf("Error applying %q", p.config.Module)
|
return fmt.Errorf("Error applying %q", p.config.Module)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -262,7 +262,7 @@ func (p *Provisioner) Provision(ctx context.Context, ui packer.Ui, comm packer.C
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd = &packer.RemoteCmd{Command: command}
|
cmd = &packer.RemoteCmd{Command: command}
|
||||||
return cmd.StartWithUi(comm, ui)
|
return cmd.RunWithUi(ctx, comm, ui)
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -271,7 +271,7 @@ func (p *Provisioner) Provision(ctx context.Context, ui packer.Ui, comm packer.C
|
||||||
// Close the original file since we copied it
|
// Close the original file since we copied it
|
||||||
f.Close()
|
f.Close()
|
||||||
|
|
||||||
if err := p.config.ValidExitCode(cmd.ExitStatus); err != nil {
|
if err := p.config.ValidExitCode(cmd.ExitStatus()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -348,12 +348,12 @@ func (p *Provisioner) Provision(ctx context.Context, ui packer.Ui, comm packer.C
|
||||||
}
|
}
|
||||||
|
|
||||||
ui.Message(fmt.Sprintf("Running Puppet: %s", command))
|
ui.Message(fmt.Sprintf("Running Puppet: %s", command))
|
||||||
if err := cmd.StartWithUi(comm, ui); err != nil {
|
if err := cmd.RunWithUi(ctx, comm, ui); err != nil {
|
||||||
return fmt.Errorf("Got an error starting command: %s", err)
|
return fmt.Errorf("Got an error starting command: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if cmd.ExitStatus != 0 && cmd.ExitStatus != 2 && !p.config.IgnoreExitCodes {
|
if cmd.ExitStatus() != 0 && cmd.ExitStatus() != 2 && !p.config.IgnoreExitCodes {
|
||||||
return fmt.Errorf("Puppet exited with a non-zero exit status: %d", cmd.ExitStatus)
|
return fmt.Errorf("Puppet exited with a non-zero exit status: %d", cmd.ExitStatus())
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.config.CleanStagingDir {
|
if p.config.CleanStagingDir {
|
||||||
|
@ -431,21 +431,22 @@ func (p *Provisioner) createDir(ui packer.Ui, comm packer.Communicator, dir stri
|
||||||
ui.Message(fmt.Sprintf("Creating directory: %s", dir))
|
ui.Message(fmt.Sprintf("Creating directory: %s", dir))
|
||||||
|
|
||||||
cmd := &packer.RemoteCmd{Command: p.guestCommands.CreateDir(dir)}
|
cmd := &packer.RemoteCmd{Command: p.guestCommands.CreateDir(dir)}
|
||||||
|
ctx := context.TODO()
|
||||||
|
|
||||||
if err := cmd.StartWithUi(comm, ui); err != nil {
|
if err := cmd.RunWithUi(ctx, comm, ui); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if cmd.ExitStatus != 0 {
|
if cmd.ExitStatus() != 0 {
|
||||||
return fmt.Errorf("Non-zero exit status.")
|
return fmt.Errorf("Non-zero exit status.")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Chmod the directory to 0777 just so that we can access it as our user
|
// Chmod the directory to 0777 just so that we can access it as our user
|
||||||
cmd = &packer.RemoteCmd{Command: p.guestCommands.Chmod(dir, "0777")}
|
cmd = &packer.RemoteCmd{Command: p.guestCommands.Chmod(dir, "0777")}
|
||||||
if err := cmd.StartWithUi(comm, ui); err != nil {
|
if err := cmd.RunWithUi(ctx, comm, ui); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if cmd.ExitStatus != 0 {
|
if cmd.ExitStatus() != 0 {
|
||||||
return fmt.Errorf("Non-zero exit status. See output above for more info.")
|
return fmt.Errorf("Non-zero exit status. See output above for more info.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -453,12 +454,14 @@ func (p *Provisioner) createDir(ui packer.Ui, comm packer.Communicator, dir stri
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provisioner) removeDir(ui packer.Ui, comm packer.Communicator, dir string) error {
|
func (p *Provisioner) removeDir(ui packer.Ui, comm packer.Communicator, dir string) error {
|
||||||
|
ctx := context.TODO()
|
||||||
|
|
||||||
cmd := &packer.RemoteCmd{Command: p.guestCommands.RemoveDir(dir)}
|
cmd := &packer.RemoteCmd{Command: p.guestCommands.RemoveDir(dir)}
|
||||||
if err := cmd.StartWithUi(comm, ui); err != nil {
|
if err := cmd.RunWithUi(ctx, comm, ui); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if cmd.ExitStatus != 0 {
|
if cmd.ExitStatus() != 0 {
|
||||||
return fmt.Errorf("Non-zero exit status.")
|
return fmt.Errorf("Non-zero exit status.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -301,12 +301,12 @@ func (p *Provisioner) Provision(ctx context.Context, ui packer.Ui, comm packer.C
|
||||||
}
|
}
|
||||||
|
|
||||||
ui.Message(fmt.Sprintf("Running Puppet: %s", command))
|
ui.Message(fmt.Sprintf("Running Puppet: %s", command))
|
||||||
if err := cmd.StartWithUi(comm, ui); err != nil {
|
if err := cmd.RunWithUi(ctx, comm, ui); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if cmd.ExitStatus != 0 && cmd.ExitStatus != 2 && !p.config.IgnoreExitCodes {
|
if cmd.ExitStatus() != 0 && cmd.ExitStatus() != 2 && !p.config.IgnoreExitCodes {
|
||||||
return fmt.Errorf("Puppet exited with a non-zero exit status: %d", cmd.ExitStatus)
|
return fmt.Errorf("Puppet exited with a non-zero exit status: %d", cmd.ExitStatus())
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.config.CleanStagingDir {
|
if p.config.CleanStagingDir {
|
||||||
|
@ -320,21 +320,22 @@ func (p *Provisioner) Provision(ctx context.Context, ui packer.Ui, comm packer.C
|
||||||
|
|
||||||
func (p *Provisioner) createDir(ui packer.Ui, comm packer.Communicator, dir string) error {
|
func (p *Provisioner) createDir(ui packer.Ui, comm packer.Communicator, dir string) error {
|
||||||
ui.Message(fmt.Sprintf("Creating directory: %s", dir))
|
ui.Message(fmt.Sprintf("Creating directory: %s", dir))
|
||||||
|
ctx := context.TODO()
|
||||||
|
|
||||||
cmd := &packer.RemoteCmd{Command: p.guestCommands.CreateDir(dir)}
|
cmd := &packer.RemoteCmd{Command: p.guestCommands.CreateDir(dir)}
|
||||||
if err := cmd.StartWithUi(comm, ui); err != nil {
|
if err := cmd.RunWithUi(ctx, comm, ui); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if cmd.ExitStatus != 0 {
|
if cmd.ExitStatus() != 0 {
|
||||||
return fmt.Errorf("Non-zero exit status. See output above for more info.")
|
return fmt.Errorf("Non-zero exit status. See output above for more info.")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Chmod the directory to 0777 just so that we can access it as our user
|
// Chmod the directory to 0777 just so that we can access it as our user
|
||||||
cmd = &packer.RemoteCmd{Command: p.guestCommands.Chmod(dir, "0777")}
|
cmd = &packer.RemoteCmd{Command: p.guestCommands.Chmod(dir, "0777")}
|
||||||
if err := cmd.StartWithUi(comm, ui); err != nil {
|
if err := cmd.RunWithUi(ctx, comm, ui); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if cmd.ExitStatus != 0 {
|
if cmd.ExitStatus() != 0 {
|
||||||
return fmt.Errorf("Non-zero exit status. See output above for more info.")
|
return fmt.Errorf("Non-zero exit status. See output above for more info.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -342,12 +343,14 @@ func (p *Provisioner) createDir(ui packer.Ui, comm packer.Communicator, dir stri
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provisioner) removeDir(ui packer.Ui, comm packer.Communicator, dir string) error {
|
func (p *Provisioner) removeDir(ui packer.Ui, comm packer.Communicator, dir string) error {
|
||||||
|
ctx := context.TODO()
|
||||||
|
|
||||||
cmd := &packer.RemoteCmd{Command: p.guestCommands.RemoveDir(dir)}
|
cmd := &packer.RemoteCmd{Command: p.guestCommands.RemoveDir(dir)}
|
||||||
if err := cmd.StartWithUi(comm, ui); err != nil {
|
if err := cmd.RunWithUi(ctx, comm, ui); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if cmd.ExitStatus != 0 {
|
if cmd.ExitStatus() != 0 {
|
||||||
return fmt.Errorf("Non-zero exit status.")
|
return fmt.Errorf("Non-zero exit status.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -231,14 +231,14 @@ func (p *Provisioner) Provision(ctx context.Context, ui packer.Ui, comm packer.C
|
||||||
Command: fmt.Sprintf(p.guestOSTypeConfig.bootstrapFetchCmd),
|
Command: fmt.Sprintf(p.guestOSTypeConfig.bootstrapFetchCmd),
|
||||||
}
|
}
|
||||||
ui.Message(fmt.Sprintf("Downloading saltstack bootstrap to /tmp/install_salt.sh"))
|
ui.Message(fmt.Sprintf("Downloading saltstack bootstrap to /tmp/install_salt.sh"))
|
||||||
if err = cmd.StartWithUi(comm, ui); err != nil {
|
if err = cmd.RunWithUi(ctx, comm, ui); err != nil {
|
||||||
return fmt.Errorf("Unable to download Salt: %s", err)
|
return fmt.Errorf("Unable to download Salt: %s", err)
|
||||||
}
|
}
|
||||||
cmd = &packer.RemoteCmd{
|
cmd = &packer.RemoteCmd{
|
||||||
Command: fmt.Sprintf("%s %s", p.sudo(p.guestOSTypeConfig.bootstrapRunCmd), p.config.BootstrapArgs),
|
Command: fmt.Sprintf("%s %s", p.sudo(p.guestOSTypeConfig.bootstrapRunCmd), p.config.BootstrapArgs),
|
||||||
}
|
}
|
||||||
ui.Message(fmt.Sprintf("Installing Salt with command %s", cmd.Command))
|
ui.Message(fmt.Sprintf("Installing Salt with command %s", cmd.Command))
|
||||||
if err = cmd.StartWithUi(comm, ui); err != nil {
|
if err = cmd.RunWithUi(ctx, comm, ui); err != nil {
|
||||||
return fmt.Errorf("Unable to install Salt: %s", err)
|
return fmt.Errorf("Unable to install Salt: %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -342,9 +342,9 @@ func (p *Provisioner) Provision(ctx context.Context, ui packer.Ui, comm packer.C
|
||||||
|
|
||||||
ui.Message(fmt.Sprintf("Running: salt-call --local %s", p.config.CmdArgs))
|
ui.Message(fmt.Sprintf("Running: salt-call --local %s", p.config.CmdArgs))
|
||||||
cmd := &packer.RemoteCmd{Command: p.sudo(fmt.Sprintf("%s --local %s", filepath.Join(p.config.SaltBinDir, "salt-call"), p.config.CmdArgs))}
|
cmd := &packer.RemoteCmd{Command: p.sudo(fmt.Sprintf("%s --local %s", filepath.Join(p.config.SaltBinDir, "salt-call"), p.config.CmdArgs))}
|
||||||
if err = cmd.StartWithUi(comm, ui); err != nil || cmd.ExitStatus != 0 {
|
if err = cmd.RunWithUi(ctx, comm, ui); err != nil || cmd.ExitStatus() != 0 {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
err = fmt.Errorf("Bad exit status: %d", cmd.ExitStatus)
|
err = fmt.Errorf("Bad exit status: %d", cmd.ExitStatus())
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Errorf("Error executing salt-call: %s", err)
|
return fmt.Errorf("Error executing salt-call: %s", err)
|
||||||
|
@ -406,13 +406,15 @@ func (p *Provisioner) uploadFile(ui packer.Ui, comm packer.Communicator, dst, sr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provisioner) moveFile(ui packer.Ui, comm packer.Communicator, dst string, src string) error {
|
func (p *Provisioner) moveFile(ui packer.Ui, comm packer.Communicator, dst string, src string) error {
|
||||||
|
ctx := context.TODO()
|
||||||
|
|
||||||
ui.Message(fmt.Sprintf("Moving %s to %s", src, dst))
|
ui.Message(fmt.Sprintf("Moving %s to %s", src, dst))
|
||||||
cmd := &packer.RemoteCmd{
|
cmd := &packer.RemoteCmd{
|
||||||
Command: p.sudo(p.guestCommands.MovePath(src, dst)),
|
Command: p.sudo(p.guestCommands.MovePath(src, dst)),
|
||||||
}
|
}
|
||||||
if err := cmd.StartWithUi(comm, ui); err != nil || cmd.ExitStatus != 0 {
|
if err := cmd.RunWithUi(ctx, comm, ui); err != nil || cmd.ExitStatus() != 0 {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
err = fmt.Errorf("Bad exit status: %d", cmd.ExitStatus)
|
err = fmt.Errorf("Bad exit status: %d", cmd.ExitStatus())
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Errorf("Unable to move %s to %s: %s", src, dst, err)
|
return fmt.Errorf("Unable to move %s to %s: %s", src, dst, err)
|
||||||
|
@ -425,38 +427,41 @@ func (p *Provisioner) createDir(ui packer.Ui, comm packer.Communicator, dir stri
|
||||||
cmd := &packer.RemoteCmd{
|
cmd := &packer.RemoteCmd{
|
||||||
Command: p.guestCommands.CreateDir(dir),
|
Command: p.guestCommands.CreateDir(dir),
|
||||||
}
|
}
|
||||||
if err := cmd.StartWithUi(comm, ui); err != nil {
|
ctx := context.TODO()
|
||||||
|
if err := cmd.RunWithUi(ctx, comm, ui); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if cmd.ExitStatus != 0 {
|
if cmd.ExitStatus() != 0 {
|
||||||
return fmt.Errorf("Non-zero exit status.")
|
return fmt.Errorf("Non-zero exit status.")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provisioner) statPath(ui packer.Ui, comm packer.Communicator, path string) error {
|
func (p *Provisioner) statPath(ui packer.Ui, comm packer.Communicator, path string) error {
|
||||||
|
ctx := context.TODO()
|
||||||
ui.Message(fmt.Sprintf("Verifying Path: %s", path))
|
ui.Message(fmt.Sprintf("Verifying Path: %s", path))
|
||||||
cmd := &packer.RemoteCmd{
|
cmd := &packer.RemoteCmd{
|
||||||
Command: p.guestCommands.StatPath(path),
|
Command: p.guestCommands.StatPath(path),
|
||||||
}
|
}
|
||||||
if err := cmd.StartWithUi(comm, ui); err != nil {
|
if err := cmd.RunWithUi(ctx, comm, ui); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if cmd.ExitStatus != 0 {
|
if cmd.ExitStatus() != 0 {
|
||||||
return fmt.Errorf("Non-zero exit status.")
|
return fmt.Errorf("Non-zero exit status.")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provisioner) removeDir(ui packer.Ui, comm packer.Communicator, dir string) error {
|
func (p *Provisioner) removeDir(ui packer.Ui, comm packer.Communicator, dir string) error {
|
||||||
|
ctx := context.TODO()
|
||||||
ui.Message(fmt.Sprintf("Removing directory: %s", dir))
|
ui.Message(fmt.Sprintf("Removing directory: %s", dir))
|
||||||
cmd := &packer.RemoteCmd{
|
cmd := &packer.RemoteCmd{
|
||||||
Command: p.guestCommands.RemoveDir(dir),
|
Command: p.guestCommands.RemoveDir(dir),
|
||||||
}
|
}
|
||||||
if err := cmd.StartWithUi(comm, ui); err != nil {
|
if err := cmd.RunWithUi(ctx, comm, ui); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if cmd.ExitStatus != 0 {
|
if cmd.ExitStatus() != 0 {
|
||||||
return fmt.Errorf("Non-zero exit status.")
|
return fmt.Errorf("Non-zero exit status.")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -26,7 +26,7 @@ func (p *Provisioner) Prepare(raws ...interface{}) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provisioner) Provision(ctx context.Context, ui packer.Ui, _ packer.Communicator) error {
|
func (p *Provisioner) Provision(ctx context.Context, ui packer.Ui, _ packer.Communicator) error {
|
||||||
_, retErr := sl.Run(ui, &p.config)
|
_, retErr := sl.Run(ctx, ui, &p.config)
|
||||||
if retErr != nil {
|
if retErr != nil {
|
||||||
return retErr
|
return retErr
|
||||||
}
|
}
|
||||||
|
|
|
@ -256,7 +256,7 @@ func (p *Provisioner) Provision(ctx context.Context, ui packer.Ui, comm packer.C
|
||||||
cmd = &packer.RemoteCmd{
|
cmd = &packer.RemoteCmd{
|
||||||
Command: fmt.Sprintf("chmod 0600 %s", remoteVFName),
|
Command: fmt.Sprintf("chmod 0600 %s", remoteVFName),
|
||||||
}
|
}
|
||||||
if err := comm.Start(cmd); err != nil {
|
if err := comm.Start(ctx, cmd); err != nil {
|
||||||
return fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"Error chmodding script file to 0600 in remote "+
|
"Error chmodding script file to 0600 in remote "+
|
||||||
"machine: %s", err)
|
"machine: %s", err)
|
||||||
|
@ -314,7 +314,7 @@ func (p *Provisioner) Provision(ctx context.Context, ui packer.Ui, comm packer.C
|
||||||
cmd = &packer.RemoteCmd{
|
cmd = &packer.RemoteCmd{
|
||||||
Command: fmt.Sprintf("chmod 0755 %s", p.config.RemotePath),
|
Command: fmt.Sprintf("chmod 0755 %s", p.config.RemotePath),
|
||||||
}
|
}
|
||||||
if err := comm.Start(cmd); err != nil {
|
if err := comm.Start(ctx, cmd); err != nil {
|
||||||
return fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"Error chmodding script file to 0755 in remote "+
|
"Error chmodding script file to 0755 in remote "+
|
||||||
"machine: %s", err)
|
"machine: %s", err)
|
||||||
|
@ -322,7 +322,7 @@ func (p *Provisioner) Provision(ctx context.Context, ui packer.Ui, comm packer.C
|
||||||
cmd.Wait()
|
cmd.Wait()
|
||||||
|
|
||||||
cmd = &packer.RemoteCmd{Command: command}
|
cmd = &packer.RemoteCmd{Command: command}
|
||||||
return cmd.StartWithUi(comm, ui)
|
return cmd.RunWithUi(ctx, comm, ui)
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -331,7 +331,7 @@ func (p *Provisioner) Provision(ctx context.Context, ui packer.Ui, comm packer.C
|
||||||
|
|
||||||
// If the exit code indicates a remote disconnect, fail unless
|
// If the exit code indicates a remote disconnect, fail unless
|
||||||
// we were expecting it.
|
// we were expecting it.
|
||||||
if cmd.ExitStatus == packer.CmdDisconnect {
|
if cmd.ExitStatus() == packer.CmdDisconnect {
|
||||||
if !p.config.ExpectDisconnect {
|
if !p.config.ExpectDisconnect {
|
||||||
return fmt.Errorf("Script disconnected unexpectedly. " +
|
return fmt.Errorf("Script disconnected unexpectedly. " +
|
||||||
"If you expected your script to disconnect, i.e. from a " +
|
"If you expected your script to disconnect, i.e. from a " +
|
||||||
|
@ -339,7 +339,7 @@ func (p *Provisioner) Provision(ctx context.Context, ui packer.Ui, comm packer.C
|
||||||
"or `\"valid_exit_codes\": [0, 2300218]` to the shell " +
|
"or `\"valid_exit_codes\": [0, 2300218]` to the shell " +
|
||||||
"provisioner parameters.")
|
"provisioner parameters.")
|
||||||
}
|
}
|
||||||
} else if err := p.config.ValidExitCode(cmd.ExitStatus); err != nil {
|
} else if err := p.config.ValidExitCode(cmd.ExitStatus()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -371,21 +371,22 @@ func (p *Provisioner) Provision(ctx context.Context, ui packer.Ui, comm packer.C
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provisioner) cleanupRemoteFile(path string, comm packer.Communicator) error {
|
func (p *Provisioner) cleanupRemoteFile(path string, comm packer.Communicator) error {
|
||||||
|
ctx := context.TODO()
|
||||||
err := p.retryable(func() error {
|
err := p.retryable(func() error {
|
||||||
cmd := &packer.RemoteCmd{
|
cmd := &packer.RemoteCmd{
|
||||||
Command: fmt.Sprintf("rm -f %s", path),
|
Command: fmt.Sprintf("rm -f %s", path),
|
||||||
}
|
}
|
||||||
if err := comm.Start(cmd); err != nil {
|
if err := comm.Start(ctx, cmd); err != nil {
|
||||||
return fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"Error removing temporary script at %s: %s",
|
"Error removing temporary script at %s: %s",
|
||||||
path, err)
|
path, err)
|
||||||
}
|
}
|
||||||
cmd.Wait()
|
cmd.Wait()
|
||||||
// treat disconnects as retryable by returning an error
|
// treat disconnects as retryable by returning an error
|
||||||
if cmd.ExitStatus == packer.CmdDisconnect {
|
if cmd.ExitStatus() == packer.CmdDisconnect {
|
||||||
return fmt.Errorf("Disconnect while removing temporary script.")
|
return fmt.Errorf("Disconnect while removing temporary script.")
|
||||||
}
|
}
|
||||||
if cmd.ExitStatus != 0 {
|
if cmd.ExitStatus() != 0 {
|
||||||
return fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"Error removing temporary script at %s!",
|
"Error removing temporary script at %s!",
|
||||||
path)
|
path)
|
||||||
|
|
|
@ -106,15 +106,15 @@ func (p *Provisioner) Provision(ctx context.Context, ui packer.Ui, comm packer.C
|
||||||
command := p.config.RestartCommand
|
command := p.config.RestartCommand
|
||||||
err := p.retryable(func() error {
|
err := p.retryable(func() error {
|
||||||
cmd = &packer.RemoteCmd{Command: command}
|
cmd = &packer.RemoteCmd{Command: command}
|
||||||
return cmd.StartWithUi(comm, ui)
|
return cmd.RunWithUi(ctx, comm, ui)
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if cmd.ExitStatus != 0 && cmd.ExitStatus != 1115 && cmd.ExitStatus != 1190 {
|
if cmd.ExitStatus() != 0 && cmd.ExitStatus() != 1115 && cmd.ExitStatus() != 1190 {
|
||||||
return fmt.Errorf("Restart script exited with non-zero exit status: %d", cmd.ExitStatus)
|
return fmt.Errorf("Restart script exited with non-zero exit status: %d", cmd.ExitStatus())
|
||||||
}
|
}
|
||||||
|
|
||||||
return waitForRestart(ctx, p, comm)
|
return waitForRestart(ctx, p, comm)
|
||||||
|
@ -141,25 +141,25 @@ var waitForRestart = func(ctx context.Context, p *Provisioner, comm packer.Commu
|
||||||
for {
|
for {
|
||||||
log.Printf("Check if machine is rebooting...")
|
log.Printf("Check if machine is rebooting...")
|
||||||
cmd = &packer.RemoteCmd{Command: trycommand}
|
cmd = &packer.RemoteCmd{Command: trycommand}
|
||||||
err = cmd.StartWithUi(comm, ui)
|
err = cmd.RunWithUi(ctx, comm, ui)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Couldn't execute, we assume machine is rebooting already
|
// Couldn't execute, we assume machine is rebooting already
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if cmd.ExitStatus == 1 {
|
if cmd.ExitStatus() == 1 {
|
||||||
// SSH provisioner, and we're already rebooting. SSH can reconnect
|
// SSH provisioner, and we're already rebooting. SSH can reconnect
|
||||||
// without our help; exit this wait loop.
|
// without our help; exit this wait loop.
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if cmd.ExitStatus == 1115 || cmd.ExitStatus == 1190 || cmd.ExitStatus == 1717 {
|
if cmd.ExitStatus() == 1115 || cmd.ExitStatus() == 1190 || cmd.ExitStatus() == 1717 {
|
||||||
// Reboot already in progress but not completed
|
// Reboot already in progress but not completed
|
||||||
log.Printf("Reboot already in progress, waiting...")
|
log.Printf("Reboot already in progress, waiting...")
|
||||||
time.Sleep(10 * time.Second)
|
time.Sleep(10 * time.Second)
|
||||||
}
|
}
|
||||||
if cmd.ExitStatus == 0 {
|
if cmd.ExitStatus() == 0 {
|
||||||
// Cancel reboot we created to test if machine was already rebooting
|
// Cancel reboot we created to test if machine was already rebooting
|
||||||
cmd = &packer.RemoteCmd{Command: abortcommand}
|
cmd = &packer.RemoteCmd{Command: abortcommand}
|
||||||
cmd.StartWithUi(comm, ui)
|
cmd.RunWithUi(ctx, comm, ui)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -221,7 +221,7 @@ var waitForCommunicator = func(ctx context.Context, p *Provisioner) error {
|
||||||
}
|
}
|
||||||
if runCustomRestartCheck {
|
if runCustomRestartCheck {
|
||||||
// run user-configured restart check
|
// run user-configured restart check
|
||||||
err := cmdRestartCheck.StartWithUi(p.comm, p.ui)
|
err := cmdRestartCheck.RunWithUi(ctx, p.comm, p.ui)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Communication connection err: %s", err)
|
log.Printf("Communication connection err: %s", err)
|
||||||
continue
|
continue
|
||||||
|
@ -243,7 +243,7 @@ var waitForCommunicator = func(ctx context.Context, p *Provisioner) error {
|
||||||
cmdModuleLoad.Stdout = &buf
|
cmdModuleLoad.Stdout = &buf
|
||||||
cmdModuleLoad.Stdout = io.MultiWriter(cmdModuleLoad.Stdout, &buf2)
|
cmdModuleLoad.Stdout = io.MultiWriter(cmdModuleLoad.Stdout, &buf2)
|
||||||
|
|
||||||
cmdModuleLoad.StartWithUi(p.comm, p.ui)
|
cmdModuleLoad.RunWithUi(ctx, p.comm, p.ui)
|
||||||
stdoutToRead := buf2.String()
|
stdoutToRead := buf2.String()
|
||||||
|
|
||||||
if !strings.Contains(stdoutToRead, "restarted.") {
|
if !strings.Contains(stdoutToRead, "restarted.") {
|
||||||
|
@ -262,7 +262,7 @@ var waitForCommunicator = func(ctx context.Context, p *Provisioner) error {
|
||||||
cmdKeyCheck.Stdout = &buf
|
cmdKeyCheck.Stdout = &buf
|
||||||
cmdKeyCheck.Stdout = io.MultiWriter(cmdKeyCheck.Stdout, &buf2)
|
cmdKeyCheck.Stdout = io.MultiWriter(cmdKeyCheck.Stdout, &buf2)
|
||||||
|
|
||||||
err := p.comm.Start(cmdKeyCheck)
|
err := p.comm.Start(ctx, cmdKeyCheck)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Communication connection err: %s", err)
|
log.Printf("Communication connection err: %s", err)
|
||||||
shouldContinue = true
|
shouldContinue = true
|
||||||
|
|
|
@ -214,7 +214,7 @@ func (p *Provisioner) Provision(ctx context.Context, ui packer.Ui, comm packer.C
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd = &packer.RemoteCmd{Command: command}
|
cmd = &packer.RemoteCmd{Command: command}
|
||||||
return cmd.StartWithUi(comm, ui)
|
return cmd.RunWithUi(ctx, comm, ui)
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -223,7 +223,7 @@ func (p *Provisioner) Provision(ctx context.Context, ui packer.Ui, comm packer.C
|
||||||
// Close the original file since we copied it
|
// Close the original file since we copied it
|
||||||
f.Close()
|
f.Close()
|
||||||
|
|
||||||
if err := p.config.ValidExitCode(cmd.ExitStatus); err != nil {
|
if err := p.config.ValidExitCode(cmd.ExitStatus()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue