Add reboot cap for windows

This commit introduces a proper reboot cap for Windows guests. Once it
initiates a reboot on the guest, it calls out to the wait_for_reboot cap
to block on until the guest is finished rebooting.
This commit is contained in:
Brian Cain 2018-11-02 13:50:54 -07:00
parent 54c8ebc31a
commit 142a6898bc
No known key found for this signature in database
GPG Key ID: 9FC4639B2E4510A0
4 changed files with 53 additions and 34 deletions

View File

@ -4,8 +4,6 @@ module VagrantPlugins
module GuestWindows
module Cap
module ChangeHostName
MAX_REBOOT_DURATION = 120
def self.change_host_name(machine, name)
change_host_name_and_wait(machine, name, machine.config.vm.graceful_halt_timeout)
end
@ -20,9 +18,6 @@ module VagrantPlugins
script = <<-EOH
$computer = Get-WmiObject -Class Win32_ComputerSystem
$retval = $computer.rename("#{name}").returnvalue
if ($retval -eq 0) {
shutdown /r /t 5 /f /d p:4:1 /c "Vagrant Rename Computer"
}
exit $retval
EOH
@ -31,24 +26,7 @@ module VagrantPlugins
error_class: Errors::RenameComputerFailed,
error_key: :rename_computer_failed)
wait_remaining = MAX_REBOOT_DURATION
begin
# Don't continue until the machine has shutdown and rebooted
if machine.guest.capability?(:wait_for_reboot)
machine.guest.capability(:wait_for_reboot)
else
@logger.debug("No wait_for_reboot capability, sleeping for #{sleep_timeout} instead...")
# use graceful_halt_timeout only if guest cannot wait for reboot
sleep(sleep_timeout)
end
rescue Vagrant::Errors::MachineGuestNotReady => e
raise if wait_remaining < 0
@logger.warn("Machine not ready, cannot wait for reboot yet. Trying again")
sleep(5)
wait_remaining -= 5
retry
end
machine.guest.capability(:reboot)
end
end
end

View File

@ -1,21 +1,50 @@
require "log4r"
module VagrantPlugins
module GuestWindows
module Cap
class Reboot
def self.wait_for_reboot(machine)
# Technically it should be possible to make it work with SSH
# too, but we don't yet.
return if machine.config.vm.communicator != :winrm
MAX_REBOOT_RETRY_DURATION = 120
def self.reboot(machine)
@logger = Log4r::Logger.new("vagrant::windows::reboot")
reboot_script = "shutdown /r /t 5 /f /d p:4:1 /c \"Vagrant Reboot Computer\""
comm = machine.communicate
script = File.expand_path("../../scripts/reboot_detect.ps1", __FILE__)
script = File.read(script)
while machine.communicate.execute(script, error_check: false) != 0
if comm.test(script, error_check: false, shell: :powershell)
@logger.debug("Issuing reboot command for guest")
comm.execute(reboot_script, shell: :powershell)
else
@logger.debug("A reboot is already in progress")
end
@logger.debug("Waiting for machine to finish rebooting")
wait_remaining = MAX_REBOOT_RETRY_DURATION
begin
wait_for_reboot(machine)
rescue Vagrant::Errors::MachineGuestNotReady, WinRM::WinRMHTTPTransportError => e
raise if wait_remaining < 0
@logger.warn("Machine not ready, cannot start reboot yet. Trying again")
sleep(5)
wait_remaining -= 5
retry
end
end
def self.wait_for_reboot(machine)
script = File.expand_path("../../scripts/reboot_detect.ps1", __FILE__)
script = File.read(script)
while machine.communicate.execute(script, error_check: false, shell: :powershell) != 0
sleep 10
end
# This re-establishes our symbolic links if they were
# created between now and a reboot
machine.communicate.execute("net use", error_check: false)
machine.communicate.execute("net use", error_check: false, shell: :powershell)
end
end
end

View File

@ -64,6 +64,11 @@ module VagrantPlugins
Cap::Reboot
end
guest_capability(:windows, :reboot) do
require_relative "cap/reboot"
Cap::Reboot
end
guest_capability(:windows, :choose_addressable_ip_addr) do
require_relative "cap/choose_addressable_ip_addr"
Cap::ChooseAddressableIPAddr

View File

@ -17,6 +17,12 @@ describe "VagrantPlugins::GuestWindows::Cap::Reboot" do
allow(config).to receive(:vm).and_return(vm)
end
describe ".reboot" do
before do
allow(vm).to receive(:communicator).and_return(:winrm)
end
end
describe "winrm communicator" do
before do
allow(vm).to receive(:communicator).and_return(:winrm)
@ -24,15 +30,15 @@ describe "VagrantPlugins::GuestWindows::Cap::Reboot" do
describe ".wait_for_reboot" do
it "runs reboot detect script" do
expect(communicator).to receive(:execute).with(/# Function/, { error_check: false }).and_return(0)
expect(communicator).to receive(:execute).with(/# Function/, { error_check: false, shell: :powershell }).and_return(0)
allow(communicator).to receive(:execute)
described_class.wait_for_reboot(machine)
end
it "fixes symlinks to network shares" do
allow(communicator).to receive(:execute).and_return(0)
expect(communicator).to receive(:execute).with('net use', { error_check: false })
expect(communicator).to receive(:execute).with('net use', { error_check: false, shell: :powershell })
described_class.wait_for_reboot(machine)
end
@ -45,8 +51,9 @@ describe "VagrantPlugins::GuestWindows::Cap::Reboot" do
end
describe ".wait_for_reboot" do
it "does not execute Windows reboot detect script" do
expect(communicator).to_not receive(:execute)
it "does execute Windows reboot detect script" do
expect(communicator).to receive(:execute).with(/# Function/, { error_check: false, shell: :powershell }).and_return(0)
expect(communicator).to receive(:execute).with('net use', { error_check: false, shell: :powershell })
described_class.wait_for_reboot(machine)
end
end