deduplicate the nearly identical communicators for the shell-local provisioner and post-processor, moving single communicator into a new common/shell-local module
This commit is contained in:
parent
23e51d21c2
commit
616b41e58f
|
@ -3,8 +3,8 @@ package chroot
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
sl "github.com/hashicorp/packer/common/shell-local"
|
||||||
"github.com/hashicorp/packer/packer"
|
"github.com/hashicorp/packer/packer"
|
||||||
"github.com/hashicorp/packer/post-processor/shell-local"
|
|
||||||
"github.com/hashicorp/packer/template/interpolate"
|
"github.com/hashicorp/packer/template/interpolate"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -21,7 +21,10 @@ func RunLocalCommands(commands []string, wrappedCommand CommandWrapper, ctx inte
|
||||||
}
|
}
|
||||||
|
|
||||||
ui.Say(fmt.Sprintf("Executing command: %s", command))
|
ui.Say(fmt.Sprintf("Executing command: %s", command))
|
||||||
comm := &shell_local.Communicator{}
|
comm := &sl.Communicator{
|
||||||
|
Ctx: ctx,
|
||||||
|
ExecuteCommand: []string{""},
|
||||||
|
}
|
||||||
cmd := &packer.RemoteCmd{Command: command}
|
cmd := &packer.RemoteCmd{Command: command}
|
||||||
if err := cmd.StartWithUi(comm, ui); err != nil {
|
if err := cmd.StartWithUi(comm, ui); err != nil {
|
||||||
return fmt.Errorf("Error executing command: %s", err)
|
return fmt.Errorf("Error executing command: %s", err)
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
package shell
|
package shell_local
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"runtime"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/hashicorp/packer/packer"
|
"github.com/hashicorp/packer/packer"
|
||||||
|
@ -17,17 +18,34 @@ type Communicator struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Communicator) Start(cmd *packer.RemoteCmd) error {
|
func (c *Communicator) Start(cmd *packer.RemoteCmd) error {
|
||||||
// Render the template so that we know how to execute the command
|
if len(c.ExecuteCommand) == 0 {
|
||||||
c.Ctx.Data = &ExecuteCommandTemplate{
|
// Get default Execute Command
|
||||||
Command: cmd.Command,
|
if runtime.GOOS == "windows" {
|
||||||
}
|
c.ExecuteCommand = []string{
|
||||||
for i, field := range c.ExecuteCommand {
|
"cmd",
|
||||||
command, err := interpolate.Render(field, &c.Ctx)
|
"/C",
|
||||||
if err != nil {
|
"{{.Command}}",
|
||||||
return fmt.Errorf("Error processing command: %s", err)
|
}
|
||||||
|
} else {
|
||||||
|
c.ExecuteCommand = []string{
|
||||||
|
"/bin/sh",
|
||||||
|
"-c",
|
||||||
|
"{{.Command}}",
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// Render the template so that we know how to execute the command
|
||||||
|
c.Ctx.Data = &ExecuteCommandTemplate{
|
||||||
|
Command: cmd.Command,
|
||||||
|
}
|
||||||
|
for i, field := range c.ExecuteCommand {
|
||||||
|
command, err := interpolate.Render(field, &c.Ctx)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error processing command: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
c.ExecuteCommand[i] = command
|
c.ExecuteCommand[i] = command
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build the local command to execute
|
// Build the local command to execute
|
|
@ -1,4 +1,4 @@
|
||||||
package shell
|
package shell_local
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
|
@ -1,63 +0,0 @@
|
||||||
package shell_local
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"github.com/hashicorp/packer/packer"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Communicator struct{}
|
|
||||||
|
|
||||||
func (c *Communicator) Start(cmd *packer.RemoteCmd) error {
|
|
||||||
localCmd := exec.Command("sh", "-c", cmd.Command)
|
|
||||||
localCmd.Stdin = cmd.Stdin
|
|
||||||
localCmd.Stdout = cmd.Stdout
|
|
||||||
localCmd.Stderr = cmd.Stderr
|
|
||||||
|
|
||||||
// Start it. If it doesn't work, then error right away.
|
|
||||||
if err := localCmd.Start(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// We've started successfully. Start a goroutine to wait for
|
|
||||||
// it to complete and track exit status.
|
|
||||||
go func() {
|
|
||||||
var exitStatus int
|
|
||||||
err := localCmd.Wait()
|
|
||||||
if err != nil {
|
|
||||||
if exitErr, ok := err.(*exec.ExitError); ok {
|
|
||||||
exitStatus = 1
|
|
||||||
|
|
||||||
// There is no process-independent way to get the REAL
|
|
||||||
// exit status so we just try to go deeper.
|
|
||||||
if status, ok := exitErr.Sys().(syscall.WaitStatus); ok {
|
|
||||||
exitStatus = status.ExitStatus()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd.SetExited(exitStatus)
|
|
||||||
}()
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Communicator) Upload(string, io.Reader, *os.FileInfo) error {
|
|
||||||
return fmt.Errorf("upload not supported")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Communicator) UploadDir(string, string, []string) error {
|
|
||||||
return fmt.Errorf("uploadDir not supported")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Communicator) Download(string, io.Writer) error {
|
|
||||||
return fmt.Errorf("download not supported")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Communicator) DownloadDir(src string, dst string, exclude []string) error {
|
|
||||||
return fmt.Errorf("downloadDir not supported")
|
|
||||||
}
|
|
|
@ -1,43 +0,0 @@
|
||||||
package shell_local
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"runtime"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/hashicorp/packer/packer"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestCommunicator_impl(t *testing.T) {
|
|
||||||
var _ packer.Communicator = new(Communicator)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCommunicator(t *testing.T) {
|
|
||||||
if runtime.GOOS == "windows" {
|
|
||||||
t.Skip("windows not supported for this test")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c := &Communicator{}
|
|
||||||
|
|
||||||
var buf bytes.Buffer
|
|
||||||
cmd := &packer.RemoteCmd{
|
|
||||||
Command: "/bin/echo foo",
|
|
||||||
Stdout: &buf,
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := c.Start(cmd); err != nil {
|
|
||||||
t.Fatalf("err: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd.Wait()
|
|
||||||
|
|
||||||
if cmd.ExitStatus != 0 {
|
|
||||||
t.Fatalf("err bad exit status: %d", cmd.ExitStatus)
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.TrimSpace(buf.String()) != "foo" {
|
|
||||||
t.Fatalf("bad: %s", buf.String())
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/hashicorp/packer/common"
|
"github.com/hashicorp/packer/common"
|
||||||
|
sl "github.com/hashicorp/packer/common/shell-local"
|
||||||
"github.com/hashicorp/packer/helper/config"
|
"github.com/hashicorp/packer/helper/config"
|
||||||
"github.com/hashicorp/packer/packer"
|
"github.com/hashicorp/packer/packer"
|
||||||
"github.com/hashicorp/packer/template/interpolate"
|
"github.com/hashicorp/packer/template/interpolate"
|
||||||
|
@ -178,7 +179,10 @@ func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (pac
|
||||||
|
|
||||||
ui.Say(fmt.Sprintf("Post processing with local shell script: %s", script))
|
ui.Say(fmt.Sprintf("Post processing with local shell script: %s", script))
|
||||||
|
|
||||||
comm := &Communicator{}
|
comm := &sl.Communicator{
|
||||||
|
Ctx: p.config.ctx,
|
||||||
|
ExecuteCommand: []string{p.config.ExecuteCommand},
|
||||||
|
}
|
||||||
|
|
||||||
cmd := &packer.RemoteCmd{Command: command}
|
cmd := &packer.RemoteCmd{Command: command}
|
||||||
|
|
||||||
|
|
|
@ -3,9 +3,9 @@ package shell
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"runtime"
|
|
||||||
|
|
||||||
"github.com/hashicorp/packer/common"
|
"github.com/hashicorp/packer/common"
|
||||||
|
sl "github.com/hashicorp/packer/common/shell-local"
|
||||||
"github.com/hashicorp/packer/helper/config"
|
"github.com/hashicorp/packer/helper/config"
|
||||||
"github.com/hashicorp/packer/packer"
|
"github.com/hashicorp/packer/packer"
|
||||||
"github.com/hashicorp/packer/template/interpolate"
|
"github.com/hashicorp/packer/template/interpolate"
|
||||||
|
@ -41,33 +41,12 @@ func (p *Provisioner) Prepare(raws ...interface{}) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(p.config.ExecuteCommand) == 0 {
|
|
||||||
if runtime.GOOS == "windows" {
|
|
||||||
p.config.ExecuteCommand = []string{
|
|
||||||
"cmd",
|
|
||||||
"/C",
|
|
||||||
"{{.Command}}",
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
p.config.ExecuteCommand = []string{
|
|
||||||
"/bin/sh",
|
|
||||||
"-c",
|
|
||||||
"{{.Command}}",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var errs *packer.MultiError
|
var errs *packer.MultiError
|
||||||
if p.config.Command == "" {
|
if p.config.Command == "" {
|
||||||
errs = packer.MultiErrorAppend(errs,
|
errs = packer.MultiErrorAppend(errs,
|
||||||
errors.New("command must be specified"))
|
errors.New("command must be specified"))
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(p.config.ExecuteCommand) == 0 {
|
|
||||||
errs = packer.MultiErrorAppend(errs,
|
|
||||||
errors.New("execute_command must not be empty"))
|
|
||||||
}
|
|
||||||
|
|
||||||
if errs != nil && len(errs.Errors) > 0 {
|
if errs != nil && len(errs.Errors) > 0 {
|
||||||
return errs
|
return errs
|
||||||
}
|
}
|
||||||
|
@ -77,7 +56,7 @@ func (p *Provisioner) Prepare(raws ...interface{}) error {
|
||||||
|
|
||||||
func (p *Provisioner) Provision(ui packer.Ui, _ packer.Communicator) error {
|
func (p *Provisioner) Provision(ui packer.Ui, _ packer.Communicator) error {
|
||||||
// Make another communicator for local
|
// Make another communicator for local
|
||||||
comm := &Communicator{
|
comm := &sl.Communicator{
|
||||||
Ctx: p.config.ctx,
|
Ctx: p.config.ctx,
|
||||||
ExecuteCommand: p.config.ExecuteCommand,
|
ExecuteCommand: p.config.ExecuteCommand,
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue