Merge pull request #4034 from mitchellh/sshdisconnect
handle case when remote ssh server disconnects
This commit is contained in:
commit
1a87d49abf
|
@ -118,15 +118,13 @@ func (c *comm) Start(cmd *packer.RemoteCmd) (err error) {
|
||||||
log.Printf("Remote command exited with '%d': %s", exitStatus, cmd.Command)
|
log.Printf("Remote command exited with '%d': %s", exitStatus, cmd.Command)
|
||||||
case *ssh.ExitMissingError:
|
case *ssh.ExitMissingError:
|
||||||
log.Printf("Remote command exited without exit status or exit signal.")
|
log.Printf("Remote command exited without exit status or exit signal.")
|
||||||
exitStatus = -1
|
exitStatus = packer.CmdDisconnect
|
||||||
default:
|
default:
|
||||||
log.Printf("Error occurred waiting for ssh session: %s", err.Error())
|
log.Printf("Error occurred waiting for ssh session: %s", err.Error())
|
||||||
exitStatus = -1
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cmd.SetExited(exitStatus)
|
cmd.SetExited(exitStatus)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,10 @@ import (
|
||||||
"github.com/mitchellh/iochan"
|
"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.
|
// RemoteCmd represents a remote command being prepared or run.
|
||||||
type RemoteCmd struct {
|
type RemoteCmd struct {
|
||||||
// Command is the command to run remotely. This is executed as if
|
// Command is the command to run remotely. This is executed as if
|
||||||
|
|
|
@ -70,6 +70,8 @@ type Config struct {
|
||||||
// Whether to clean scripts up
|
// Whether to clean scripts up
|
||||||
SkipClean bool `mapstructure:"skip_clean"`
|
SkipClean bool `mapstructure:"skip_clean"`
|
||||||
|
|
||||||
|
ExpectDisconnect *bool `mapstructure:"expect_disconnect"`
|
||||||
|
|
||||||
startRetryTimeout time.Duration
|
startRetryTimeout time.Duration
|
||||||
ctx interpolate.Context
|
ctx interpolate.Context
|
||||||
}
|
}
|
||||||
|
@ -101,6 +103,11 @@ func (p *Provisioner) Prepare(raws ...interface{}) error {
|
||||||
p.config.ExecuteCommand = "chmod +x {{.Path}}; {{.Vars}} {{.Path}}"
|
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 {
|
if p.config.Inline != nil && len(p.config.Inline) == 0 {
|
||||||
p.config.Inline = nil
|
p.config.Inline = nil
|
||||||
}
|
}
|
||||||
|
@ -283,11 +290,18 @@ func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error {
|
||||||
cmd = &packer.RemoteCmd{Command: command}
|
cmd = &packer.RemoteCmd{Command: command}
|
||||||
return cmd.StartWithUi(comm, ui)
|
return cmd.StartWithUi(comm, ui)
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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)
|
return fmt.Errorf("Script exited with non-zero exit status: %d", cmd.ExitStatus)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,11 +32,42 @@ func TestProvisionerPrepare_Defaults(t *testing.T) {
|
||||||
t.Fatalf("err: %s", err)
|
t.Fatalf("err: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if *p.config.ExpectDisconnect != true {
|
||||||
|
t.Errorf("expected ExpectDisconnect to be true")
|
||||||
|
}
|
||||||
|
|
||||||
if p.config.RemotePath == "" {
|
if p.config.RemotePath == "" {
|
||||||
t.Errorf("unexpected remote path: %s", 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) {
|
func TestProvisionerPrepare_InlineShebang(t *testing.T) {
|
||||||
config := testConfig()
|
config := testConfig()
|
||||||
|
|
||||||
|
|
|
@ -71,6 +71,10 @@ Optional parameters:
|
||||||
available variables: `Path`, which is the path to the script to run, and
|
available variables: `Path`, which is the path to the script to run, and
|
||||||
`Vars`, which is the list of `environment_vars`, if configured.
|
`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
|
- `inline_shebang` (string) - The
|
||||||
[shebang](https://en.wikipedia.org/wiki/Shebang_%28Unix%29) value to use when
|
[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
|
running commands specified by `inline`. By default, this is `/bin/sh -e`. If
|
||||||
|
|
Loading…
Reference in New Issue