Add install_timeout to stop build if step_wait takes too long

Halts the build when the VM does not shutdown within the timeout period
Implemented with interruptible_wait, so step_wait is also interruptible
This commit is contained in:
Cheng Sun 2014-12-08 17:49:07 +00:00
parent 1dd963278f
commit cadf3a5d6a
3 changed files with 35 additions and 14 deletions

View File

@ -35,10 +35,9 @@ type config struct {
HostPortMax uint `mapstructure:"host_port_max"` HostPortMax uint `mapstructure:"host_port_max"`
BootCommand []string `mapstructure:"boot_command"` BootCommand []string `mapstructure:"boot_command"`
RawBootWait string `mapstructure:"boot_wait"`
BootWait time.Duration `` RawBootWait string `mapstructure:"boot_wait"`
SSHWaitTimeout time.Duration `` BootWait time.Duration ``
ISOChecksum string `mapstructure:"iso_checksum"` ISOChecksum string `mapstructure:"iso_checksum"`
ISOChecksumType string `mapstructure:"iso_checksum_type"` ISOChecksumType string `mapstructure:"iso_checksum_type"`
@ -52,7 +51,11 @@ type config struct {
LocalIp string `mapstructure:"local_ip"` LocalIp string `mapstructure:"local_ip"`
PlatformArgs map[string]string `mapstructure:"platform_args"` PlatformArgs map[string]string `mapstructure:"platform_args"`
RawSSHWaitTimeout string `mapstructure:"ssh_wait_timeout"` RawInstallTimeout string `mapstructure:"install_timeout"`
InstallTimeout time.Duration ``
RawSSHWaitTimeout string `mapstructure:"ssh_wait_timeout"`
SSHWaitTimeout time.Duration ``
SSHPassword string `mapstructure:"ssh_password"` SSHPassword string `mapstructure:"ssh_password"`
SSHUser string `mapstructure:"ssh_username"` SSHUser string `mapstructure:"ssh_username"`
@ -100,6 +103,10 @@ func (self *Builder) Prepare(raws ...interface{}) (params []string, retErr error
self.config.RawBootWait = "5s" self.config.RawBootWait = "5s"
} }
if self.config.RawInstallTimeout == "" {
self.config.RawInstallTimeout = "200m"
}
if self.config.HTTPPortMin == 0 { if self.config.HTTPPortMin == 0 {
self.config.HTTPPortMin = 8000 self.config.HTTPPortMin = 8000
} }
@ -133,6 +140,7 @@ func (self *Builder) Prepare(raws ...interface{}) (params []string, retErr error
"iso_checksum_type": &self.config.ISOChecksumType, "iso_checksum_type": &self.config.ISOChecksumType,
"http_directory": &self.config.HTTPDir, "http_directory": &self.config.HTTPDir,
"local_ip": &self.config.LocalIp, "local_ip": &self.config.LocalIp,
"install_timeout": &self.config.RawInstallTimeout,
"ssh_wait_timeout": &self.config.RawSSHWaitTimeout, "ssh_wait_timeout": &self.config.RawSSHWaitTimeout,
"ssh_username": &self.config.SSHUser, "ssh_username": &self.config.SSHUser,
"ssh_password": &self.config.SSHPassword, "ssh_password": &self.config.SSHPassword,
@ -167,6 +175,12 @@ func (self *Builder) Prepare(raws ...interface{}) (params []string, retErr error
errs, fmt.Errorf("Failed to parse ssh_wait_timeout: %s", err)) errs, fmt.Errorf("Failed to parse ssh_wait_timeout: %s", err))
} }
self.config.InstallTimeout, err = time.ParseDuration(self.config.RawInstallTimeout)
if err != nil {
errs = packer.MultiErrorAppend(
errs, fmt.Errorf("Failed to parse install_timeout: %s", err))
}
for i, command := range self.config.BootCommand { for i, command := range self.config.BootCommand {
if err := self.config.tpl.Validate(command); err != nil { if err := self.config.tpl.Validate(command); err != nil {
errs = packer.MultiErrorAppend(errs, errs = packer.MultiErrorAppend(errs,

View File

@ -9,27 +9,33 @@ import (
type stepWait struct{} type stepWait struct{}
func (self *stepWait) Run(state multistep.StateBag) multistep.StepAction { func (self *stepWait) Run(state multistep.StateBag) multistep.StepAction {
config := state.Get("config").(config)
ui := state.Get("ui").(packer.Ui) ui := state.Get("ui").(packer.Ui)
client := state.Get("client").(XenAPIClient) client := state.Get("client").(XenAPIClient)
ui.Say("Step: Wait for install to complete.") ui.Say("Step: Wait for install to complete.")
//Expect install to be configured to shutdown on completion
instance_id := state.Get("instance_uuid").(string) instance_id := state.Get("instance_uuid").(string)
instance, _ := client.GetVMByUuid(instance_id) instance, _ := client.GetVMByUuid(instance_id)
for { //Expect install to be configured to shutdown on completion
time.Sleep(30 * time.Second) err := InterruptibleWait{
ui.Say("Waiting for VM install...") Predicate: func () (bool, error) {
power_state, err := instance.GetPowerState()
return power_state == "Halted", err
},
PredicateInterval: 30 * time.Second,
Timeout: config.InstallTimeout,
}.Wait(state)
power_state, _ := instance.GetPowerState() if err != nil {
if power_state == "Halted" { ui.Error(err.Error())
ui.Say("Install has completed. Moving on.") ui.Error("Giving up waiting for installation to complete.")
break return multistep.ActionHalt
}
} }
ui.Say("Install has completed. Moving on.")
// Eject ISO from drive // Eject ISO from drive
vbds, _ := instance.GetVBDs() vbds, _ := instance.GetVBDs()
for _, vbd := range vbds { for _, vbd := range vbds {

View File

@ -10,6 +10,7 @@
"iso_name": "CentOS-6.4-x86_64-minimal.iso", "iso_name": "CentOS-6.4-x86_64-minimal.iso",
"http_directory": "http", "http_directory": "http",
"local_ip": "10.80.3.223", "local_ip": "10.80.3.223",
"install_timeout": "600",
"ssh_username": "root", "ssh_username": "root",
"ssh_password": "vmpassword", "ssh_password": "vmpassword",
"boot_command": "boot_command":