diff --git a/provisioner/windows-restart/provisioner.go b/provisioner/windows-restart/provisioner.go index 2e4b7c371..6b7bd90d3 100644 --- a/provisioner/windows-restart/provisioner.go +++ b/provisioner/windows-restart/provisioner.go @@ -13,9 +13,11 @@ import ( "github.com/mitchellh/packer/template/interpolate" ) -var DefaultRestartCommand = "powershell \"& {Restart-Computer -force }\"" +var DefaultRestartCommand = "shutdown /r /f /t 0 /c \"packer restart\"" var DefaultRestartCheckCommand = winrm.Powershell(`echo "${env:COMPUTERNAME} restarted."`) var retryableSleep = 5 * time.Second +var TryCheckReboot = "shutdown.exe -f -r -t 60" +var AbortReboot = "shutdown.exe -a" type Config struct { common.PackerConfig `mapstructure:",squash"` @@ -94,16 +96,42 @@ func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error { return fmt.Errorf("Restart script exited with non-zero exit status: %d", cmd.ExitStatus) } - return waitForRestart(p) + return waitForRestart(p, comm) } -var waitForRestart = func(p *Provisioner) error { +var waitForRestart = func(p *Provisioner, comm packer.Communicator) error { ui := p.ui ui.Say("Waiting for machine to restart...") waitDone := make(chan bool, 1) timeout := time.After(p.config.RestartTimeout) var err error + p.comm = comm + var cmd *packer.RemoteCmd + trycommand := TryCheckReboot + abortcommand := AbortReboot + // Stolen from Vagrant reboot checker + for { + log.Printf("Check if machine is rebooting...") + cmd = &packer.RemoteCmd{Command: trycommand} + err = cmd.StartWithUi(comm, ui) + if err != nil { + // Couldnt execute, we asume machine is rebooting already + break + } + if cmd.ExitStatus == 1115 || cmd.ExitStatus == 1190 { + // Reboot already in progress but not completed + log.Printf("Reboot already in progress, waiting...") + time.Sleep(10 * time.Second) + } + if cmd.ExitStatus == 0 { + // Cancel reboot we created to test if machine was already rebooting + cmd = &packer.RemoteCmd{Command: abortcommand} + cmd.StartWithUi(comm, ui) + break + } + } + go func() { log.Printf("Waiting for machine to become available...") err = waitForCommunicator(p) diff --git a/provisioner/windows-restart/provisioner_test.go b/provisioner/windows-restart/provisioner_test.go index 9baf65845..5f7afc25f 100644 --- a/provisioner/windows-restart/provisioner_test.go +++ b/provisioner/windows-restart/provisioner_test.go @@ -35,7 +35,7 @@ func TestProvisionerPrepare_Defaults(t *testing.T) { t.Errorf("unexpected remote path: %s", p.config.RestartTimeout) } - if p.config.RestartCommand != "powershell \"& {Restart-Computer -force }\"" { + if p.config.RestartCommand != "shutdown /r /f /t 0 /c \"packer restart\"" { t.Errorf("unexpected remote path: %s", p.config.RestartCommand) } } @@ -100,6 +100,10 @@ func TestProvisionerProvision_Success(t *testing.T) { waitForCommunicator = func(p *Provisioner) error { return nil } + waitForRestartOld := waitForRestart + waitForRestart = func(p *Provisioner, comm packer.Communicator) error { + return nil + } err := p.Provision(ui, comm) if err != nil { t.Fatal("should not have error") @@ -113,6 +117,7 @@ func TestProvisionerProvision_Success(t *testing.T) { } // Set this back! waitForCommunicator = waitForCommunicatorOld + waitForRestart = waitForRestartOld } func TestProvisionerProvision_CustomCommand(t *testing.T) { @@ -131,6 +136,10 @@ func TestProvisionerProvision_CustomCommand(t *testing.T) { waitForCommunicator = func(p *Provisioner) error { return nil } + waitForRestartOld := waitForRestart + waitForRestart = func(p *Provisioner, comm packer.Communicator) error { + return nil + } err := p.Provision(ui, comm) if err != nil { t.Fatal("should not have error") @@ -142,6 +151,7 @@ func TestProvisionerProvision_CustomCommand(t *testing.T) { } // Set this back! waitForCommunicator = waitForCommunicatorOld + waitForRestart = waitForRestartOld } func TestProvisionerProvision_RestartCommandFail(t *testing.T) {