Merge pull request #4034 from mitchellh/sshdisconnect

handle case when remote ssh server disconnects
This commit is contained in:
Matthew Hooker 2016-10-21 12:48:40 -07:00 committed by GitHub
commit 1a87d49abf
5 changed files with 55 additions and 4 deletions

View File

@ -118,15 +118,13 @@ func (c *comm) Start(cmd *packer.RemoteCmd) (err error) {
log.Printf("Remote command exited with '%d': %s", exitStatus, cmd.Command)
case *ssh.ExitMissingError:
log.Printf("Remote command exited without exit status or exit signal.")
exitStatus = -1
exitStatus = packer.CmdDisconnect
default:
log.Printf("Error occurred waiting for ssh session: %s", err.Error())
exitStatus = -1
}
}
cmd.SetExited(exitStatus)
}()
return
}

View File

@ -9,6 +9,10 @@ import (
"github.com/mitchellh/iochan"
)
// CmdDisconnect is a sentry value to indicate a RemoteCmd
// exited because the remote side disconnected us.
const CmdDisconnect int = 2300218
// RemoteCmd represents a remote command being prepared or run.
type RemoteCmd struct {
// Command is the command to run remotely. This is executed as if

View File

@ -70,6 +70,8 @@ type Config struct {
// Whether to clean scripts up
SkipClean bool `mapstructure:"skip_clean"`
ExpectDisconnect *bool `mapstructure:"expect_disconnect"`
startRetryTimeout time.Duration
ctx interpolate.Context
}
@ -101,6 +103,11 @@ func (p *Provisioner) Prepare(raws ...interface{}) error {
p.config.ExecuteCommand = "chmod +x {{.Path}}; {{.Vars}} {{.Path}}"
}
if p.config.ExpectDisconnect == nil {
t := true
p.config.ExpectDisconnect = &t
}
if p.config.Inline != nil && len(p.config.Inline) == 0 {
p.config.Inline = nil
}
@ -283,11 +290,18 @@ func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error {
cmd = &packer.RemoteCmd{Command: command}
return cmd.StartWithUi(comm, ui)
})
if err != nil {
return err
}
if cmd.ExitStatus != 0 {
// If the exit code indicates a remote disconnect, fail unless
// we were expecting it.
if cmd.ExitStatus == packer.CmdDisconnect {
if !*p.config.ExpectDisconnect {
return fmt.Errorf("Script disconnected unexpectedly.")
}
} else if cmd.ExitStatus != 0 {
return fmt.Errorf("Script exited with non-zero exit status: %d", cmd.ExitStatus)
}

View File

@ -32,11 +32,42 @@ func TestProvisionerPrepare_Defaults(t *testing.T) {
t.Fatalf("err: %s", err)
}
if *p.config.ExpectDisconnect != true {
t.Errorf("expected ExpectDisconnect to be true")
}
if p.config.RemotePath == "" {
t.Errorf("unexpected remote path: %s", p.config.RemotePath)
}
}
func TestProvisionerPrepare_ExpectDisconnect(t *testing.T) {
config := testConfig()
p := new(Provisioner)
config["expect_disconnect"] = false
err := p.Prepare(config)
if err != nil {
t.Fatalf("err: %s", err)
}
if *p.config.ExpectDisconnect != false {
t.Errorf("expected ExpectDisconnect to be false")
}
config["expect_disconnect"] = true
p = new(Provisioner)
err = p.Prepare(config)
if err != nil {
t.Fatalf("err: %s", err)
}
if *p.config.ExpectDisconnect != true {
t.Errorf("expected ExpectDisconnect to be true")
}
}
func TestProvisionerPrepare_InlineShebang(t *testing.T) {
config := testConfig()

View File

@ -71,6 +71,10 @@ Optional parameters:
available variables: `Path`, which is the path to the script to run, and
`Vars`, which is the list of `environment_vars`, if configured.
- `expect_disconnect` (bool) - Defaults to true. Whether to error if the
server disconnects us. A disconnect might happen if you restart the ssh
server or reboot the host. May default to false in the future.
- `inline_shebang` (string) - The
[shebang](https://en.wikipedia.org/wiki/Shebang_%28Unix%29) value to use when
running commands specified by `inline`. By default, this is `/bin/sh -e`. If