provisioner/shell: start_retry_timeout for reboot handling [GH-260]
This commit is contained in:
parent
90974a4733
commit
21f92715c0
|
@ -1,6 +1,10 @@
|
||||||
## 0.3.1 (unreleased)
|
## 0.3.1 (unreleased)
|
||||||
|
|
||||||
|
IMPROVEMENTS:
|
||||||
|
|
||||||
|
* provisioner/shell: New setting `start_retry_timeout` which is the timeout
|
||||||
|
for the provisioner to attempt to _start_ the remote process. This allows
|
||||||
|
the shell provisioner to work properly with reboots. [GH-260]
|
||||||
|
|
||||||
## 0.3.0 (August 12, 2013)
|
## 0.3.0 (August 12, 2013)
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
const DefaultRemotePath = "/tmp/script.sh"
|
const DefaultRemotePath = "/tmp/script.sh"
|
||||||
|
@ -45,7 +46,13 @@ type config struct {
|
||||||
// can be used to inject the environment_vars into the environment.
|
// can be used to inject the environment_vars into the environment.
|
||||||
ExecuteCommand string `mapstructure:"execute_command"`
|
ExecuteCommand string `mapstructure:"execute_command"`
|
||||||
|
|
||||||
tpl *common.Template
|
// The timeout for retrying to start the process. Until this timeout
|
||||||
|
// is reached, if the provisioner can't start a process, it retries.
|
||||||
|
// This can be set high to allow for reboots.
|
||||||
|
RawStartRetryTimeout string `mapstructure:"start_retry_timeout"`
|
||||||
|
|
||||||
|
startRetryTimeout time.Duration
|
||||||
|
tpl *common.Template
|
||||||
}
|
}
|
||||||
|
|
||||||
type Provisioner struct {
|
type Provisioner struct {
|
||||||
|
@ -84,6 +91,10 @@ func (p *Provisioner) Prepare(raws ...interface{}) error {
|
||||||
p.config.InlineShebang = "/bin/sh"
|
p.config.InlineShebang = "/bin/sh"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if p.config.RawStartRetryTimeout == "" {
|
||||||
|
p.config.RawStartRetryTimeout = "5m"
|
||||||
|
}
|
||||||
|
|
||||||
if p.config.RemotePath == "" {
|
if p.config.RemotePath == "" {
|
||||||
p.config.RemotePath = DefaultRemotePath
|
p.config.RemotePath = DefaultRemotePath
|
||||||
}
|
}
|
||||||
|
@ -106,9 +117,10 @@ func (p *Provisioner) Prepare(raws ...interface{}) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
templates := map[string]*string{
|
templates := map[string]*string{
|
||||||
"inline_shebang": &p.config.InlineShebang,
|
"inline_shebang": &p.config.InlineShebang,
|
||||||
"script": &p.config.Script,
|
"script": &p.config.Script,
|
||||||
"remote_path": &p.config.RemotePath,
|
"start_retry_timeout": &p.config.RawStartRetryTimeout,
|
||||||
|
"remote_path": &p.config.RemotePath,
|
||||||
}
|
}
|
||||||
|
|
||||||
for n, ptr := range templates {
|
for n, ptr := range templates {
|
||||||
|
@ -161,6 +173,14 @@ func (p *Provisioner) Prepare(raws ...interface{}) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if p.config.RawStartRetryTimeout != "" {
|
||||||
|
p.config.startRetryTimeout, err = time.ParseDuration(p.config.RawStartRetryTimeout)
|
||||||
|
if err != nil {
|
||||||
|
errs = packer.MultiErrorAppend(
|
||||||
|
errs, fmt.Errorf("Failed parsing start_retry_timeout: %s", err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if errs != nil && len(errs.Errors) > 0 {
|
if errs != nil && len(errs.Errors) > 0 {
|
||||||
return errs
|
return errs
|
||||||
}
|
}
|
||||||
|
@ -238,9 +258,26 @@ func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := &packer.RemoteCmd{Command: command}
|
cmd := &packer.RemoteCmd{Command: command}
|
||||||
|
startTimeout := time.After(p.config.startRetryTimeout)
|
||||||
log.Printf("Executing command: %s", cmd.Command)
|
log.Printf("Executing command: %s", cmd.Command)
|
||||||
if err := cmd.StartWithUi(comm, ui); err != nil {
|
for {
|
||||||
return fmt.Errorf("Failed executing command: %s", err)
|
if err := cmd.StartWithUi(comm, ui); err == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create an error and log it
|
||||||
|
err = fmt.Errorf("Error executing command: %s", err)
|
||||||
|
log.Printf(err.Error())
|
||||||
|
|
||||||
|
// Check if we timed out, otherwise we retry. It is safe to
|
||||||
|
// retry since the only error case above is if the command
|
||||||
|
// failed to START.
|
||||||
|
select {
|
||||||
|
case <-startTimeout:
|
||||||
|
return err
|
||||||
|
default:
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if cmd.ExitStatus != 0 {
|
if cmd.ExitStatus != 0 {
|
||||||
|
|
|
@ -67,6 +67,12 @@ Optional parameters:
|
||||||
in the machine. This defaults to "/tmp/script.sh". This value must be
|
in the machine. This defaults to "/tmp/script.sh". This value must be
|
||||||
a writable location and any parent directories must already exist.
|
a writable location and any parent directories must already exist.
|
||||||
|
|
||||||
|
* `start_retry_timeout` (string) - The amount of time to attempt to
|
||||||
|
_start_ the remote process. By default this is "5m" or 5 minutes. This
|
||||||
|
setting exists in order to deal with times when SSH may restart, such as
|
||||||
|
a system reboot. Set this to a higher value if reboots take a longer
|
||||||
|
amount of time.
|
||||||
|
|
||||||
## Execute Command Example
|
## Execute Command Example
|
||||||
|
|
||||||
To many new users, the `execute_command` is puzzling. However, it provides
|
To many new users, the `execute_command` is puzzling. However, it provides
|
||||||
|
|
Loading…
Reference in New Issue